1. 程式人生 > 程式設計 >Flink 系列(一)—— Flink 核心概念綜述

Flink 系列(一)—— Flink 核心概念綜述

一、Flink 簡介

Apache Flink 誕生於柏林工業大學的一個研究性專案,原名 StratoSphere 。2014 年,由 StratoSphere 專案孵化出 Flink,並於同年捐贈 Apache,之後成為 Apache 的頂級專案。2019 年 1 年,阿里巴巴收購了 Flink 的母公司 Data Artisans,並宣佈開源內部的 Blink,Blink 是阿里巴巴基於 Flink 優化後的版本,增加了大量的新功能,並在效能和穩定性上進行了各種優化,經歷過阿里內部多種複雜業務的挑戰和檢驗。同時阿里巴巴也表示會逐步將這些新功能和特性 Merge 回社群版本的 Flink 中,因此 Flink 成為目前最為火熱的大資料處理框架。

簡單來說,Flink 是一個分散式的流處理框架,它能夠對有界和無界的資料流進行高效的處理。Flink 的核心是流處理,當然它也能支援批處理,Flink 將批處理看成是流處理的一種特殊情況,即資料流是有明確界限的。這和 Spark Streaming 的思想是完全相反的,Spark Streaming 的核心是批處理,它將流處理看成是批處理的一種特殊情況, 即把資料流進行極小粒度的拆分,拆分為多個微批處理。

Flink 有界資料流和無界資料流:

https://github.com/heibaiying

Spark Streaming 資料流的拆分:

https://github.com/heibaiying

二、Flink 核心架構

Flink 採用分層的架構設計,從而保證各層在功能和職責上的清晰。如下圖所示,由上而下分別是 API & Libraries 層、Runtime 核心層以及物理部署層:

2.1 API & Libraries 層

這一層主要提供了程式設計 API 和 頂層類庫:

  • 程式設計 API : 用於進行流處理的 DataStream API 和用於進行批處理的 DataSet API;
  • 頂層類庫:包括用於複雜事件處理的 CEP 庫;用於結構化資料查詢的 SQL & Table 庫,以及基於批處理的機器學習庫 FlinkML 和 圖形處理庫 Gelly。

2.2 Runtime 核心層

這一層是 Flink 分散式計算框架的核心實現層,包括作業轉換,任務排程,資源分配,任務執行等功能,基於這一層的實現,可以在流式引擎下同時執行流處理程式和批處理程式。

2.3 物理部署層

Flink 的物理部署層,用於支援在不同平臺上部署執行 Flink 應用。

三、Flink 分層 API

在上面介紹的 API & Libraries 這一層,Flink 又進行了更為具體的劃分。具體如下:

https://github.com/heibaiying

按照如上的層次結構,API 的一致性由下至上依次遞增,介面的表現能力由下至上依次遞減,各層的核心功能如下:

3.1 SQL & Table API

SQL & Table API 同時適用於批處理和流處理,這意味著你可以對有界資料流和無界資料流以相同的語義進行查詢,併產生相同的結果。除了基本查詢外, 它還支援自定義的標量函式,聚合函式以及表值函式,可以滿足多樣化的查詢需求。

3.2 DataStream & DataSet API

DataStream & DataSet API 是 Flink 資料處理的核心 API,支援使用 Java 語言或 Scala 語言進行呼叫,提供了資料讀取,資料轉換和資料輸出等一系列常用操作的封裝。

3.3 Stateful Stream Processing

Stateful Stream Processing 是最低階別的抽象,它通過 Process Function 函式內嵌到 DataStream API 中。 Process Function 是 Flink 提供的最底層 API,具有最大的靈活性,允許開發者對於時間和狀態進行細粒度的控制。

四、Flink 叢集架構

4.1 核心元件

按照上面的介紹,Flink 核心架構的第二層是 Runtime 層, 該層採用標準的 Master - Slave 結構, 其中,Master 部分又包含了三個核心元件:Dispatcher、ResourceManager 和 JobManager,而 Slave 則主要是 TaskManager 程式。它們的功能分別如下:

  • JobManagers (也稱為 masters) :JobManagers 接收由 Dispatcher 傳遞過來的執行程式,該執行程式包含了作業圖 (JobGraph),邏輯資料流圖 (logical dataflow graph) 及其所有的 classes 檔案以及第三方類庫 (libraries) 等等 。緊接著 JobManagers 會將 JobGraph 轉換為執行圖 (ExecutionGraph),然後向 ResourceManager 申請資源來執行該任務,一旦申請到資源,就將執行圖分發給對應的 TaskManagers 。因此每個作業 (Job) 至少有一個 JobManager;高可用部署下可以有多個 JobManagers,其中一個作為 leader,其餘的則處於 standby 狀態。
  • TaskManagers (也稱為 workers) : TaskManagers 負責實際的子任務 (subtasks) 的執行,每個 TaskManagers 都擁有一定數量的 slots。Slot 是一組固定大小的資源的合集 (如計算能力,儲存空間)。TaskManagers 啟動後,會將其所擁有的 slots 註冊到 ResourceManager 上,由 ResourceManager 進行統一管理。
  • Dispatcher:負責接收客戶端提交的執行程式,並傳遞給 JobManager 。除此之外,它還提供了一個 WEB UI 介面,用於監控作業的執行情況。
  • ResourceManager :負責管理 slots 並協調叢集資源。ResourceManager 接收來自 JobManager 的資源請求,並將存在空閒 slots 的 TaskManagers 分配給 JobManager 執行任務。Flink 基於不同的部署平臺,如 YARN,Mesos,K8s 等提供了不同的資源管理器,當 TaskManagers 沒有足夠的 slots 來執行任務時,它會向第三方平臺發起會話來請求額外的資源。

https://github.com/heibaiying

4.2 Task & SubTask

上面我們提到:TaskManagers 實際執行的是 SubTask,而不是 Task,這裡解釋一下兩者的區別:

在執行分散式計算時,Flink 將可以連結的操作 (operators) 連結到一起,這就是 Task。之所以這樣做, 是為了減少執行緒間切換和緩衝而導致的開銷,在降低延遲的同時可以提高整體的吞吐量。 但不是所有的 operator 都可以被連結,如下 keyBy 等操作會導致網路 shuffle 和重分割槽,因此其就不能被連結,只能被單獨作為一個 Task。 簡單來說,一個 Task 就是一個可以連結的最小的操作鏈 (Operator Chains) 。如下圖,source 和 map 運算元被連結到一塊,因此整個作業就只有三個 Task:

https://github.com/heibaiying

解釋完 Task ,我們在解釋一下什麼是 SubTask,其準確的翻譯是: A subtask is one parallel slice of a task,即一個 Task 可以按照其並行度拆分為多個 SubTask。如上圖,source & map 具有兩個並行度,KeyBy 具有兩個並行度,Sink 具有一個並行度,因此整個雖然只有 3 個 Task,但是卻有 5 個 SubTask。Jobmanager 負責定義和拆分這些 SubTask,並將其交給 Taskmanagers 來執行,每個 SubTask 都是一個單獨的執行緒。

4.3 資源管理

理解了 SubTasks ,我們再來看看其與 Slots 的對應情況。一種可能的分配情況如下:

https://github.com/heibaiying

這時每個 SubTask 執行緒執行在一個獨立的 TaskSlot, 它們共享所屬的 TaskManager 程式的TCP 連線(通過多路複用技術)和心跳資訊 (heartbeat messages),從而可以降低整體的效能開銷。此時看似是最好的情況,但是每個操作需要的資源都是不盡相同的,這裡假設該作業 keyBy 操作所需資源的數量比 Sink 多很多 ,那麼此時 Sink 所在 Slot 的資源就沒有得到有效的利用。

基於這個原因,Flink 允許多個 subtasks 共享 slots,即使它們是不同 tasks 的 subtasks,但只要它們來自同一個 Job 就可以。假設上面 souce & map 和 keyBy 的並行度調整為 6,而 Slot 的數量不變,此時情況如下:

https://github.com/heibaiying

可以看到一個 Task Slot 中運行了多個 SubTask 子任務,此時每個子任務仍然在一個獨立的執行緒中執行,只不過共享一組 Sot 資源而已。那麼 Flink 到底如何確定一個 Job 至少需要多少個 Slot 呢?Flink 對於這個問題的處理很簡單,預設情況一個 Job 所需要的 Slot 的數量就等於其 Operation 操作的最高並行度。如下, A,B,D 操作的並行度為 4,而 C,E 操作的並行度為 2,那麼此時整個 Job 就需要至少四個 Slots 來完成。通過這個機制,Flink 就可以不必去關心一個 Job 到底會被拆分為多少個 Tasks 和 SubTasks。

https://github.com/heibaiying

4.4 元件通訊

Flink 的所有元件都基於 Actor System 來進行通訊。Actor system是多種角色的 actor 的容器,它提供排程,配置,日誌記錄等多種服務,幷包含一個可以啟動所有 actor 的執行緒池,如果 actor 是本地的,則訊息通過共享記憶體進行共享,但如果 actor 是遠端的,則通過 RPC 的呼叫來傳遞訊息。

https://github.com/heibaiying

五、Flink 的優點

最後基於上面的介紹,來總結一下 Flink 的優點:

  • Flink 是基於事件驅動 (Event-driven) 的應用,能夠同時支援流處理和批處理;
  • 基於記憶體的計算,能夠保證高吞吐和低延遲,具有優越的效能表現;
  • 支援精確一次 (Exactly-once) 語意,能夠完美地保證一致性和正確性;
  • 分層 API ,能夠滿足各個層次的開發需求;
  • 支援高可用配置,支援儲存點機制,能夠提供安全性和穩定性上的保證;
  • 多樣化的部署方式,支援本地,遠端,雲端等多種部署方案;
  • 具有橫向擴充套件架構,能夠按照使用者的需求進行動態擴容;
  • 活躍度極高的社群和完善的生態圈的支援。

參考資料

更多大資料系列文章可以參見 GitHub 開源專案大資料入門指南