Flink FAQ - Task 之間的數據交換

翻譯自原文:https://cwiki.apache.org/confluence/display/FLINK/Data+exchange+between+tasks

Flink中的數據交換基於以下設計原則構建:

  1. 數據交換的流控是由接收方啓動的,這與原始MapReduce十分相似。
  2. 用於數據交換的數據流,即通過物理線路的實際數據傳輸,是通過IntermediateResult的概念抽象的,並且是可插入的。這意味着該系統可以使用相同的實現方式去支持流式傳輸(streaming)與批量傳輸(batch)

數據交換的過程:

數據交換的過程,涉及多個對象,包括:

作爲主節點的JobManager負責安排任務,恢復和協調,並通過ExecutionGraph數據結構掌握工作的概況。

TaskManagers,工作節點。TaskManager(TM)在線程中同時執行許多任務。每個TM還包含一個CommunicationManager(CM-在任務之間共享)和一個MemoryManager(MM-在任務之間共享)。 TaskManager可以通過複用的TCP連接相互交換數據,這些連接是在需要時創建的。

請注意,在Flink中,通過網絡交換數據的是TaskManagers(而不是task),位於同一TaskManagers中的任務之間的數據交換,是通過一個網絡連接進行多路複用的。

 

執行圖:執行圖是一個包含關於作業計算的“最基本事實”的數據結構。

它由表示計算任務的頂點(ExecutionVertex EV)和表示任務生成的數據的中間結果(IntermediateResultPartition )組成。頂點通過執行邊(EE)鏈接到它們消耗的中間結果:

 

這些是位於JobManager中的邏輯數據結構。在taskmanager上進行實際數據處理的時候,由它們各自的運行時等效結構來負責。與IntermediateResultPartition等價的運行時數據結構稱爲ResultPartition。

下圖所示爲數據在一個 taskmanager 內的流轉:

ResultPartition (RP)表示BufferWriter寫入的數據塊,即由單個任務產生的數據塊。RS 是結果子分區(RSs)的集合。這是爲了區分發送給不同接收者的數據,例如,對於reduce或join的分區轉移。

ResultSubpartition (RS)表示操作符創建的數據的一個分區,以及將數據轉發給接收操作符的邏輯。因此 RS 的具體實現決定了實際的數據傳輸邏輯,這也是一種允許系統支持各種數據傳輸的 可插拔的機制。例如:PipelinedSubpartition 是一個支持流數據交換的流水線實現。SpillableSubpartition是一個支持批處理數據交換的阻塞實現。RS 的存在屏蔽了底層的數據傳輸細節。

InputGate: 邏輯上等價於接收端的RP。它負責收集數據緩衝區並將它們向上傳遞。

InputChannel: 邏輯上等價於接收端的RS。它負責收集特定分區的數據緩衝區。

序列化器(Serializer) 將各種數據類型的記錄轉換爲raw bytes buffer,反序列化器(Deserializer)在將bytes 流轉成所需的數據類型,並以此機制來處理橫跨多個緩衝區的記錄。

buffer 細節可以參照:https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=53741525

 

數據交換控制流程:

該圖表示一個有兩個並行任務的簡單map-reduce作業。圖中有兩個taskmanager,每個任務(一個map和一個reduce)在兩個不同的節點上運行,JobManager在第三個節點上運行,然後我們來關注一下 在任務M1和R2之間的數據流轉,圖中:數據傳輸用粗箭頭表示,消息用細箭頭表示。

  1. 首先,M1生成一個ResultPartition (RP1)(箭頭1),當RP可用時,它通知JobManager(箭頭2)。
  2. JobManager通知此分區(任務R1和R2) 的接收方分區已經準備好。如果接收器還沒就緒,就會實際觸發任務的部署(箭頭3a, 3b)。
  3. 接收方(任務R1和R2)就緒後, 數據請求開始(箭頭4a和4b) ,這時會啓動任務(箭頭5a和5b)之間的數據傳輸,傳輸可以是local模式(5a),或者跨任務管理器進行(5b)。
  4. "RP通知JobManager自己的可用性",這個過程本身會存在一定的自由性。eg. 如果RP1在通知JobManager之前就已經 fully produce了(可能已經落盤永久化了),則這種數據交換就大致相當於Hadoop中的批處理。如果RP1在它的第一個記錄生成時就通知JM,這就是一個流式的數據交換。

 

兩個任務之間 字節緩衝區的傳輸:

 

這個圖展示了更多數據流在生產者和消費者之間的傳輸的細節:

最初,MapDriver生成一些記錄 並傳遞給RecordWriter(由收集器收集)。
RecordWriter包含許多Serializer(記錄序列化器對象),每個consumer task 都可能會消費這些記錄
例如,在shuffle 或broadcast 模式中,Serializer的數量與consumer task的數量相同。ChannelSelector 把一條記錄塞給一個或者多個Serializer。
如果記錄被廣播,那每個Serializer 都會受到這條記錄。如果記錄是哈希分區的(hash-partitioned),ChannelSelector會計算記錄的哈希值,然後選擇適當的序列化器。

Serializer將記錄序列化成bytes 數組,並將它們放在固定大小的buffer中(一條記錄可以跨多個buffer)。
之後 將這些buffer交給BufferWriter並將其寫入ResultPartition (RP)中。一個ResultPartition由幾個子分區(ResultSubpartitions RSs)組成,它們爲特定的consumers收集buffer。
在上圖中,緩衝區被指給第二個reducer (在TaskManager 2中),並被放置在RS2中。
因此,在通知JobManager後, RS2 成爲了第一個緩衝區,在消費的過程中可以使用(注意: 這個行爲實現了流轉移)。

JobManager查找RS2的消費者,並通知TaskManager 2有一組數據可用。
發送到TM2的消息傳播到InputChannel,InputChannel接收這個緩衝區,然後通知RS2可以啓動網絡傳輸。
隨後,RS2將buffer交給TM1的網絡堆棧,然後交給netty。這些個Network connection  是存在於TaskManager之間的長鏈接,Task之間不存在Network connection。

一旦buffer到達TaskManager2,它通過一個從InputChannel開始的,類似的層次結構,傳輸到inputGate(包含幾個ICs),最後抵達一個Deserializer, Deserializer從buffer中取出bytes
解析後再傳到下游接收方中去,上圖所示的接收方是一個ReduceDriver。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章