目錄
任務和操作算子鏈(Tasks and Operator Chains)
作業管理器、任務管理器和客戶端(Job Managers, Task Managers, Clients)
任務槽和資源(Task Slots and Resources)
任務和操作算子鏈(Tasks and Operator Chains)
對於分佈式執行,Flink將操作算子子任務(operator subtasks)連接到一起形成多個任務(tasks)。每個任務(筆者注:應該是子任務)由一個線程執行。將操作算子鏈接成任務是一種有用的優化:它減少了線程到線程的切換和緩衝開銷,提高了總體吞吐量,同時減少了延遲。
下圖中的示例數據流(Dataflow)由5個子任務執行,因此有5個並行線程。
圖的上半部分是Dataflow簡圖,有3個任務構成。第一個任務(Source和map())由兩個 操作算子構成一個任務鏈。圖的下半部分是Dataflow的並行視角,第一個任務由兩個並行子任務,第二個任務也是由兩個並行子任務構成,每個子任務由一個線程運行,所以共有5個線程。總之,一個任務可以分成並行的子任務,而一個子任務由一個線程單獨執行,每個子任務可能含有單個操作算子,可能含有多個操作算子構成的操作算子鏈。
作業管理器、任務管理器和客戶端(Job Managers, Task Managers, Clients)
Flink運行時(runtime )由兩種類型的進程組成:
(1)JobManagers
JobManagers(也叫masters)協調分佈式執行。它們調度任務、協調檢查點、協調故障恢復等等。集羣至少有一個作業管理器,高可用(HA)集羣有多個jobmanager,其中一個是leader,其他是備用的(standby)。
(2)TaskManagers
TaskManagers(也叫workers)執行數據流(Dataflow)的任務(或者更具體地說,子任務),緩衝和交環數據流(data streams)。必須始終至少有一個TaskManager。
JobManagers 和TaskManagers 可以以各種方式啓動:作爲獨立集羣(standalone cluster)直接在機器上啓動,或者在容器中啓動,或者由Yarn或Mesos等資源框架管理。TaskManagers連接到JobManagers,通知它們可用,然後被分配任務。
客戶端(Client)不是運行時和程序執行的一部分,但用於準備數據流(Dataflow)並將其發送到JobManager。之後,客戶端可以斷開連接,或者保持連接以接收進度報告(progress reports)。客戶端可以作爲觸發執行的Java/Scala程序的一部分運行,也可以在命令行進程中運行。
圖中Flink集羣有一個master和2個works構成。從圖中能看到以下幾點:
(1)Flink Program是將程序代碼生成數據流圖(Dataflow graph),然後客戶端通過Actor System將提交給JobManager,(2)JobManager可以對任務進行調度,檢查點協調。JobManager將任務發送給TaskManager執行,JobManager可以停止或者取消任務執行;
(3)TaskManager具體來執行任務,同時將任務狀態,心跳或者統計報告發送給JobManager。JobManger會將統計結果發送給客戶端進行狀態更新。
任務槽和資源(Task Slots and Resources)
每個worker (TaskManager)都是一個JVM進程,可以在單獨的線程中執行一個子任務。爲了控制一個worker接受多少個任務,一個worker至少有一個的任務槽(Task Slots)。
每個任務槽表示TaskManager的一個固定資源子集。例如,一個有3個槽的TaskManager,會將其管理的內存的1/3分配給每個槽,也就是每個槽分配到1/3資源。對資源進行分槽意味着子任務不會與其他作業的子任務爭奪管理內存(managed memory),而是擁有一定數量的保留內存。注意,這裏沒有發生CPU隔離,當前插槽只分隔任務的託管內存。
通過調整TaskManager的任務槽的數量,用戶可以定義子任務如何相互隔離。如果每個TaskManager有一個槽意味着每個任務組在單獨的JVM中運行,如果有多個槽意味着更多的子任務共享同一個JVM。這樣相同JVM中的任務共享TCP連接和heartbeat消息,共享數據集和數據結構,從而減少每個任務的開銷。
圖中繪製了兩個TaskManager,每個TaskManager對應一個JVM進程。每個進程中有3個任務槽構成,每個任務槽中有一個線程(可以含多個線程)。任務槽中是具體執行的子任務。注意到的是:Source和map()構成的任務並行度是2,每個TaskManager執行一個,keyBy()任務也是,而Sink任務的並行度是1,由第一個TaskManager執行,所以第二個TaskManager的任務槽是空的。
默認情況下,Flink允許子任務共享插槽,即使它們是不同任務的子任務,只要它們來自相同的作業。這樣,一個插槽可以容納作業的整個管道。允許這種插槽共享有兩個主要好處:
(1)Flink集羣需要的任務槽數與作業中使用的最高並行度相同。不需要計算一個程序總共包含多少任務(具有不同的並行性)。
(2)更容易獲得更好的資源利用。
圖中是兩個TaskManger,與之前不同的是,一個job的任務可以共享任務槽,將並行度從2提升到了6,最後一個任務槽也被利用上了。一個任務槽中含有多個線程。
狀態後端(State Backends)
存儲鍵/值索引的確切數據結構取決於所選擇的狀態後端。一個狀態後端將數據存儲在內存中的散列映射中,另一個狀態後端使用RocksDB作爲鍵/值存儲。除了定義保存狀態的數據結構外,狀態後端還實現了一個邏輯:獲取鍵/值狀態的時間點快照並將該快照存儲爲檢查點的一部分。
保存點(Savepoints)
在Data Stream API 中編寫的程序可以從保存點恢復執行。保存點允許更新程序和Flink集羣而不會丟失任何狀態。保存點是手動觸發的檢查點,它獲取程序的快照並將其寫入到狀態後端。它們依賴於常規的檢查點(checkpoints )機制。在執行過程中,程序定期快照工作節點併產生檢查點。對於恢復,只需要最後一個完成的檢查點,當一個新的檢查點完成時,舊的檢查點可以被安全地丟棄。保存點與這些定期檢查點類似,不同之處在於它們是由用戶觸發的,並且在完成新的檢查點時不會自動過期。保存點可以從命令行創建,也可以在通過REST API取消作業時創建。