本文是參考官方文檔結合自己的理解寫的,所引用文獻均已指明來源,若侵權請留言告知,我會立馬刪除。此外,若是表達欠妥的地方,歡迎大伙留言指出。
前言
在上一篇博客Flink原理(二) ——資源一文中已簡要說了在Flink集群中資源的分配情況,這篇博客嘗試從定義算子之后,任務是如何分配的,以及任務是如何使用資源的。
一、Task和Operator Chains
Flink會在生成JobGraph階段,將代碼中可以優化的算子優化成一個算子鏈(Operator Chains)以放到一個task(一個線程)中執行,以減少線程之間的切換和緩沖的開銷,提高整體的吞吐量和延遲。下面以官網中的例子進行說明,如下圖1所示:
圖中,source、map、[keyBy|window|apply]、sink算子的並行度分別是2、2、2、2、1,經過Flink優化后,source和map算子組成一個算子鏈,作為一個task運行在一個線程上,其簡圖如圖中condensed view所示,並行圖如parallelized view所示。算子之間是否可以組成一個Operator Chains,看是否滿足以下條件:
- 上下游算子的並行度一致
- 下游節點的入度為1
- 上下游節點都在同一個 slot group 中
- 下游節點的 chain 策略為 ALWAYS(可以與上下游鏈接,map、flatmap、filter等默認是ALWAYS)
- 上游節點的 chain 策略為 ALWAYS 或 HEAD(只能與下游鏈接,不能與上游鏈接,Source默認是HEAD)
- 兩個節點間數據分區方式是 forward
- 用戶沒有禁用 chain(代碼中是否配置disableChain())
二、Task slot和resource
結合之前資源一文,我們可以得知上文中的任務在Flink集群中的分布應如下圖2所示:
圖中,有兩個節點(TaskManage,即兩個進程),每個節點中有3個slot,每一個task(一個Thread)均跑在一個slot中。
但實際上,Flink在默認情況下,只要子任務是來自同一個Job,是允許子任務(subtask,就是類似source/map、window等)共享一個slot的,即使是不同任務的子任務也是可以共享一個slot。這樣有兩個好處:
1) 一個Job的最高並行度就是Flink集群中slot的個數,這樣我們就不需要計算一個程序可以包含多個task;
2) 可以獲得更好的資源利用率。若沒有slot共享,像source/map這種不是非常耗資源的算子(官網上是說非資源密集型、non-intensive)就和window這種非常耗資源的算子占用相同多的資源(一個slot),如圖2所示;若允許slot共享,則圖2中集群最大的並行度可為6,如下圖3所示:
在可以共享slot的情況下,較耗資源的subtask就可以比較均勻的分布在Flink集群中的taskManager上。什么意思了?如圖3,類似window的算子均勻的分布在每個slot中,而圖2中,僅在兩個slot中。從圖3中我們也可以看出一個slot中可以運行多個Thread。