1. 程式人生 > >Apache Flink 官方文件--概念

Apache Flink 官方文件--概念

資料流程式設計模型

原文連結
博主理解篇

抽象層次

  Flink提供不同級別的抽象來開發流/批處理應用程式。

Apache Flink 官方文件--概念

  • 這個最低級別的抽象提供了有狀態的流式操作。它是通過處理函式嵌入到DataStream API。它允許使用者自由的處理一個或者多個數據流中的事件,並且使用一致,容錯的狀態。此外,使用者可以註冊事件時間和處理時間回撥,允許程式實現複雜的計算。
  • 實際上,大多數應用不需要上面描述的低級別抽象,而是針對Core APIs(核心API),例如: DataStream API(有邊界和無邊界的資料流) 和 DataSet API(有邊界的資料集)。這些流暢的API提供通用資料處理,像使用者指定的各種形式的transformations(轉換),joins(連線),aggregations(聚合),windows(視窗化操作),state(狀態)等等。這些API表示在各自的程式語言中為類(class)中的資料型別進行處理。

  低階的處理函式集成了DataStream API,這樣就可以針對特性的操作使用低層級的抽象。DataSet API 為有邊界的 data sets提供了附加的原語,例如迴圈/迭代。

  • Table API 是一種以表為中心的宣告式的DSL,它可能會被動態的改變(當處理資料流的時候)。Table API 遵循擴充套件模型:Table 有一個附加模式(類似於關係型資料庫表)並且API提供了類似的操作,例如:select,project,join,group-by,aggregate等等。Table API宣告式的定義了邏輯操作應該怎麼做 而不是確切的指定操作的程式碼看起來如何。儘管table API可以通過多種形式的使用者自定義函式來擴充套件,它的表現還是不如Core APIs,但是用起來更加的簡潔(寫更少的程式碼)。此外,Table API 還可以執行一個優化器,適用於優化規則之前執行。
      Table和DataStream/DataSet之間可以無縫的轉換,允許程式組合使用Table api和DataStream和DataSet的API。
  • Flink最高級別的抽象是sql。這種抽象在語義和表達上面類似於Table API,但將程式表示為SQL查詢表示式。SQL抽象與Table API 緊密聯絡在一起,Sql查詢可以在table API定義的表中執行。

    程式和資料流

      Flink程式的基本構建模組是streams(流)和transformations(轉換)。(需要注意的是,Flink的DataSet API所使用的DataSets內部也是流-更多內容將在以後解釋)。從概念上講流(可能沒有結束)是一個數據流記錄,而轉換是一個操作,它取一種或者多個流作為輸入,併產生一個或者多個輸出流作為結果。
      當執行的時候,Flink程式對映到streaming dataflows

    (流資料流),由streams和轉換operators組成。每一個數據流開始於一個或者多個source,並且終止於一個或者多個sink。資料流類似於任意的有向無環圖(DAGS)。雖然通過迭代構造允許特定形式的環,但是大多數情況下,簡單起見,我們都不考慮這一點。
    Apache Flink 官方文件--概念
      通常情況下,程式中的轉換與資料流中的操作是一一對應的。有時,然而,一個轉換可能有多個轉換操作構成。
      source和sink的文件在streaming connectorsbatch connectors 。Transformation的文件在DataStream operatorsDataSet transformation

    並行資料流

      Flink程式本質上是並行的和分散式的。在執行過程中,一個流(stream)包含一個或多個流分割槽 (stream partition),而每一個operator包含一個或多個operator子任務 。操作子任務之間彼此獨立,在不同的執行緒中執行,甚至有可能執行在不同的機器或容器上。
      operator子任務的數量即是此特定operator的並行度 。一個流的並行度即其生產operator的並行度。相同程式中的不同的operator可能有不同級別的並行度。
    Apache Flink 官方文件--概念
      流在兩個operator之間傳輸資料,可以通過一對一(或稱 forwarding )模式,或者通過redistributing模式:

  • 一對一流(例如上圖中Source與map() opreator之間)保持了元素的分割槽與排序。那意味著 map() operator的子任務[1]將以與 Source 的子任務[1]生成順序相同的順序檢視到相同的元素。
  • Redistributing 流(如上圖中 map() 與 keyBy/window 之間,以及 keyBy/window 與 Sink 之間)則改變了流的分割槽。每一個operator子任務根據所選擇的轉換,向不同的目標子任務傳送資料。比如 keyBy() (根據key的雜湊值重新分割槽), broadcast() ,或者 rebalance() (隨機重分割槽)。在一次 redistributing 交換中,元素間的排序只保留在每對傳送與接受子任務中(比如, map() 的子任務[1]與 keyBy/window 的子任務[2])。因此在這個例子中,每個鍵的順序被保留下來,但是並行確實引入了不確定性--對於不同鍵的聚合結果到達sink的順序。
      配置和並行度的詳細配置可以檢視這個文件parallel execution

    視窗(Window)

      聚合事件(比如計數、求和)在流上的工作方式與批處理不同。比如,對流中的所有元素進行計數是不可能的,因為通常流是無限的(無邊界的)。相反,流上的聚合需要由視窗來劃定範圍,比如 “計算過去的5分鐘” ,或者 “最後100個元素的和” 。
      視窗可以是事件驅動的 (比如:每30秒)或者資料驅動的 (比如:每100個元素)。視窗通常被區分為不同的型別,比如滾動視窗 (沒有重疊), 滑動視窗 (有重疊),以及會話視窗(由不活動的間隙所打斷)
    Apache Flink 官方文件--概念
      更多的視窗例子可以檢視這個部落格。更多的明細可以檢視視窗文件window docs

時間(Time)

  當提到流程式(例如定義視窗)中的時間時,你可以參考不同的時間概念:

  • 事件時間是事件建立的時間。它通常由事件中的時間戳描述,例如附接在生產感測器,或者生產服務。Flink通過時間戳分配器訪問事件時間戳。
  • 攝入時間是事件進入Flink資料流源算符的時間。
  • 處理時間 是每一個執行時間操作的operator的本地時間。
    Apache Flink 官方文件--概念
    操作時間的更多詳細資訊請檢視文件event time docs

有狀態的操作

  儘管資料流中的很多操作一次只檢視一個獨立的事件(比如事件解析器),有些操作卻會記錄多個事件間的資訊(比如視窗算符)。 這些操作被稱為有狀態的
  有狀態操作的狀態儲存在一個可被視作嵌入式鍵/值儲存的部分中。狀態由有狀態operator讀取的流一起被嚴格地分割槽與分佈。因此,只能訪問一個 keyBy() 函式之後的 keyed streams 的鍵/值狀態,並且僅限於與當前事件鍵相關聯的值。調整流和狀態的鍵確保了所有狀態更新都是本地操作,以在沒有事務開銷的情況下確保一致性。這種對齊還使得Flink可以透明地重新分配狀態與調整流的分割槽。
Apache Flink 官方文件--概念
檢視更多資訊,請檢視此文件有關state的內容。

容錯檢查點

  Flink使用流重放檢查點的結合實現了容錯。檢查點與每個輸入流的特定點及與相關的每一個operator的狀態相關。一個數據流可以從一個檢查點恢復出來,其中通過恢復operator狀態並從檢查點重放事件以保持一致性 (一次處理語義)
  檢查點間隔是以恢復時間(需要重放的事件數量)來消除執行過程中容錯的開銷的一種手段。
  容錯內部的描述提供了更多關於flink管理檢查點和相關的話題。啟用和配置檢查點的詳細資訊請檢視這個文件checkpointing API docs

流式批處理

  Flink將批處理程式作為流處理程式的特殊情況來執行,只是流是有界的(有限個元素)。 DataSet 內部被視為資料流。上述適用於流處理程式的概念同樣適用於批處理程式,除了一些例外:

  • 批處理程式的容錯不再使用檢查點。而是通過完全地重放流來恢復。因為輸入是有界的,因此這是可行的。這種方法使得恢復的成本增加,但是由於避免了檢查點,因而使得正常處理的開銷更小。
  • DataSet API中的有狀態操作使用簡化的im-memory/out-of-core資料結構,而不是鍵/值索引。
  • DataSet API引入了特殊的同步(superstep-base)迭代,而這種迭代僅僅能在有界流上執行。細節可以檢視迭代文件

分散式執行時

任務和Operator鏈

  對於分散式執行,Flink將operator子任務連結在一起放入任務池。每個任務由一個執行緒執行。將operator連結到任務池中是一項有用的優化:它減少執行緒到執行緒的切換和緩衝的開銷,並在降低延遲的同時提高整體吞吐量。可以配置連結行為,有關詳細資訊,請查閱連結文件
  下圖中的示例資料流由五個子任務執行,因此有五個並行執行緒。
Apache Flink 官方文件--概念

作業管理器,工作管理員,客戶端

  Flink執行時有兩種型別的程序組成:

  • 作業管理器(JobManagers,也稱為主節點master)負責協調分散式執行時。它們排程任務,協調檢查點,協調失敗恢復,等。
      至少有一個作業管理器節點,高可用的環境有多個作業管理器,其中一個節點是leader角色,其他節點是standby角色。
  • 工作管理員(TaskManagers,也稱為工作節點worker)執行資料流的任務(更特定一些,子任務),緩衝以及轉換資料流。
      同樣至少有一個工作管理員節點。
      作業管理器與工作管理員可以以多種方式啟動:以standalone叢集的方式直接在主機上啟動,或者被資源管理器YARNMesos管理啟動。工作管理員連線到作業管理器上,宣告它們自己是可用狀態並且可被分配任務。
      客戶端不是程式執行時的一部分,但是經常用來準備以及傳送資料流程式到作業管理器上。此後,客戶端可以斷開連線,或者保持連線結束程序報告。客戶端可以以Java/Scala程式的方式觸發執行,或者在命令列"./bin/flink"中執行。
    Apache Flink 官方文件--概念

    Task Slot和資源

      每個Worker節點(工作管理員)是一個JVM程序,在分開的執行緒中可以執行一個或多個子任務。一個Worker通過控制task slots(至少一個)來控制節點接受多少任務。
      每個task slot代表工作管理員固定大小的資源子集。例如:一個擁有3個slot的工作管理員,將會分配它管理的1/3記憶體到每個slot。對資源進行分槽(slot)意味著子任務不會與其他作業的子任務競爭管理的記憶體,而是具有一定數量的保留管理記憶體。注意此處沒有CPU隔離發生,現在只能分隔任務的管理記憶體。
       通過調整task slot數目,使用者可以定義子任務之間如何隔離。每個工作管理員擁有一個slot意味著任務組執行在隔離的JVM(例如,可以在隔離的容器上啟動)上。擁有多個slots意味著更多的子任務共享相同的JVM。在相同的JVM上的任務共享TCP連線(通過多路複用)和心跳資訊。它們還可以共享資料集和資料結構,從而減少每個任務的開銷。
    Apache Flink 官方文件--概念
       預設情況下,Flink允許子任務共享slot,即使它們是不同任務的子任務,只要它們來自同一個作業。結果就是一個slot擁有這個作業的所有管道操作(pipeline)。允許這種slot共享有兩個主要的好處:

  • Flink叢集需要與作業中使用的最高並行度同樣的task slots。無需計算程式總共包含多少任務(在不同的並行度之上)。
  • 更容易獲得更好的資源利用率。沒有共享slot的情況下,非密集型的source與map()子任務將會阻塞與資源密集型的視窗子任務同樣多的資源。通過共享slot,將並行度從2增加到6可以充分利用the slotted(時隙)資源,同時確保繁重的子任務在工作管理員上公平的分配。
    Apache Flink 官方文件--概念
      APIs同樣還包括用於防止不期望的slot共享的資源組機制。
      根據經驗,一個很好的預設任務槽(task slot)數就是CPU核心數。使用超執行緒,每個slot需要2個或更多硬體執行緒上下文。

狀態後端(State Backends)

  儲存鍵/值對索引的確切資料結構取決於所選的狀態後端。一個狀態後端將資料儲存在記憶體中的雜湊對映中,另一個狀態後端使用[RocksDB]()作為鍵/值對儲存。除了定義儲存狀態的資料結構之外,狀態後端還實現邏輯以獲取鍵/值對狀態的時間點快照,並將該快照儲存為檢查點的一部分。
Apache Flink 官方文件--概念

儲存點Savepoints

  用Data Stream API編寫的程式可以從儲存點恢復執行。儲存點允許更新程式和Flink叢集,而不會丟失任何狀態。
  儲存點手動觸發的檢查點,它會獲取程式的快照並將其寫入狀態後端。他們依靠常規的檢查點機制。在執行期間,程式會定期在工作節點上建立快照並生成檢查點。對於恢復,僅僅需要最後完成的檢查點,因此一旦新的檢查點完成,就可以安全地丟棄舊的檢查點。
  儲存點與這些定期檢查點類似,不同之處在於它們由使用者觸發,並且在較新的檢查點完成時不會自動過期。可以從命令列或通過REST API取消作業時建立儲存點。