關注公衆号:<code>大資料技術派</code>,回複“資料”,領取1000G資料。 本文首發于我的個人部落格:Flink 是如何統一批流引擎的
2015 年,Flink 的作者就寫了 Apache Flink: Stream and Batch Processing in a Single Engine 這篇論文。本文以這篇論文為引導,詳細講講 Flink 内部是如何設計并實作批流一體的架構。
通常我們在 Flink 中說批流一體指的是這四個方向,其中 Runtime 便是 Flink 運作時的實作。
Flink 對于流作業和批作業有一個統一的執行模型。
Flink 中每個 Task 的輸出會以 IntermediateResult 做封裝,内部并沒有對流和批兩種作業做一個明确的劃分,隻是通過不同類型的 IntermediateResult 來表達 PIPELINED 和 BLOCKING 這兩大類資料交換模型。
在了解資料交換模型之前,我們來看下為什麼 Flink 對作業類型不作區分,這樣的好處是什麼?
如上圖所示,假如我們有一個工作需要将批式作業執行結果作為流式作業的啟動輸入,那怎麼辦?這個作業是算批作業還是流作業?
很顯然,以我們的常識是無法定義的,而現有的工業界的辦法也是如此,将這個作業拆分為兩個作業,先跑批式作業,再跑流式作業,這樣當然可以,但是人工運維的成本也是足夠大的:
需要一個外界存儲來管理批作業的輸出資料。
需要一個支援批流作業依賴的排程系統。
如果期望實作這樣一個作業,那麼首先執行這個作業的計算引擎的作業屬性就不能對批作業和流作業進行強綁定。那麼 Flink 能否實作這樣的需求呢?我們先來看看資料交換的具體細節,最後再來一起看看這個作業的可行性。
我們以 PIPELINED 資料交換模型為例,看看是如何設計的:
PIPELINED 模式下,RecordWriter 将資料放入到 Buffer 中,根據 Key 的路由規則發送給對應的 Partition,Partition 将自己的資料封裝到 Reader 中放入隊列,讓 Netty Server 從隊列中讀取資料,發送給下遊。
我們将資料交換模式改為 BLOCKING,會發現這個設計也是同樣可行的。Partition 将資料寫入到檔案,而 Reader 中維護着檔案的句柄,上遊任務結束後排程下遊任務,而下遊任務通過 Netty Client 的 Partition Request 喚醒對應的 Partition 和 Reader,将資料拉到下遊。
有 LAZY 和 EAGER 兩種排程模型,預設情況下流作業使用 EAGER,批作業使用 LAZY。
這個很好了解,因為流式作業是 All or Nothing 的設計,要麼所有 Task 都 Run 起來,要麼就不跑。
LAZY 模式就是先排程上遊,等待上遊産生資料或結束後再排程下遊。有些類似 Spark 中的 Stage 執行模式。
可以看到,不管是 EAGER 還是 LAZY 都沒有辦法執行我們剛才提出的批流混合的任務,于是社群提出了 Region Scheduling 來統一批流作業的排程,我們先看一下如何定義 Region:
以 Join 算子為例,我們都知道如果 Join 算子的兩個輸入都是海量資料的話,那麼我們是需要等兩個輸入的資料都完全準備好才能進行 Join 操作的,是以 Join 兩條輸入的邊對應的資料交換模式對應的應該是 BLOCKING 模式,我們可以根據 BLOCKING 的邊将作業劃分為多個子 Region,如上圖虛線所示。
如果實作了 Region Scheduling 之後,我們在上面提到的批流混合的作業就可以将深色部分流式作業劃為一個 Region,淺色部分批式作業再劃分為多個 Region,而淺色部分是深色部分 Region 的輸入,是以根據 Region Scheduling 的原則會優先排程最前面的 Region。
上面提到了資料交換模型和排程模型,簡單來講其實就兩句話:
1 實作了用 PIPELINED 模型去跑批式作業
用 PIPELINED 模型跑流式作業和用 BLOCKING 模型跑批式作業都是沒有什麼新奇的。這裡提到用 PIPELINED 模式跑批作業,主要是針對實時分析的場景,以 Spark 為例,在大部分出現 Shuffle 或是聚合的場景下都會出現落盤的行為,并且排程順序是一個一個 Stage 進行排程,極大地降低了資料處理的實時性,而使用 PIPELINED 模式會對性能有一定提升。
可能有人會問類似 Join 的算子如何使用 PIPELINED 資料交換模型實作不落盤的操作?事實上 Flink 也會落盤,隻不過不是在 Join 的兩個輸入端落盤,而是将兩個輸入端的資料傳輸到 Join 算子上,記憶體撐不住時再進行落盤,海量資料下和 Spark 的行為并沒有本質差別,但是在資料量中等,記憶體可容納的情況下會帶來很大的收益。
2 內建了一部分排程系統的功能
根據 Region 來排程作業時,Region 内部跑的具體是流作業還是批作業,Flink 自身是不關心的,更關心的 Region 之間的依賴關系,一定程度上,利用這種排程模型我們可以将過去需要拆分為多個作業的執行模式放到一個作業中來執行,比如上面提到的批流混合的作業。