一. Flink的引入
這幾年大資料的飛速發展,出現了很多熱門的開源社群,其中著名的有 Hadoop、Storm,以及後來的 Spark,他們都有着各自專注的應用場景。Spark 掀開了記憶體計算的先河,也以記憶體為賭注,赢得了記憶體計算的飛速發展。Spark 的火熱或多或少的掩蓋了其他分布式計算的系統身影。就像 Flink,也就在這個時候默默的發展着。
在國外一些社群,有很多人将大資料的計算引擎分成了 4 代,當然,也有很多人不會認同。我們先姑且這麼認為和讨論。
首先第一代的計算引擎,無疑就是 Hadoop 承載的 MapReduce。這裡大家應該都不會對 MapReduce 陌生,它将計算分為兩個階段,分别為 Map 和 Reduce。對于上層應用來說,就不得不想方設法去拆分算法,甚至于不得不在上層應用實作多個 Job 的串聯,以完成一個完整的算法,例如疊代計算。
由于這樣的弊端,催生了支援 DAG 架構的産生。是以,支援 DAG 的架構被劃分為第二代計算引擎。如 Tez 以及更上層的 Oozie。這裡我們不去細究各種 DAG 實作之間的差別,不過對于當時的 Tez 和 Oozie 來說,大多還是批處理的任務。
接下來就是以 Spark 為代表的第三代的計算引擎。第三代計算引擎的特點主要是 Job 内部的 DAG 支援(不跨越 Job),以及強調的實時計算。在這裡,很多人也會認為第三代計算引擎也能夠很好的運作批處理的 Job。
随着第三代計算引擎的出現,促進了上層應用快速發展,例如各種疊代計算的性能以及對流計算和 SQL 等的支援。Flink 的誕生就被歸在了第四代。這應該主要表現在 Flink 對流計算的支援,以及更一步的實時性上面。當然 Flink 也可以支援 Batch 的任務,以及 DAG 的運算。
二. Flink簡介
Apache Flink是一個架構和分布式處理引擎,用于對無界和有界資料流進行有狀态計算。Flink設計為在所有常見的叢集環境中運作,以記憶體速度和任何規模執行計算。
1.無界流和有界流
任何類型的資料都是作為事件流産生的。信用卡交易,傳感器測量,機器日志或網站或移動應用程式上的使用者互動,所有這些資料都作為流生成。
資料可以作為無界或有界流處理。
- 無界流有一個開始但沒有定義的結束。它們不會在生成時終止并提供資料。必須持續處理無界流,即必須在攝取事件後立即處理事件。無法等待所有輸入資料到達,因為輸入是無界的,并且在任何時間點都不會完成。處理無界資料通常要求以特定順序(例如事件發生的順序)攝取事件,以便能夠推斷結果完整性。
- 有界流具有定義的開始和結束。可以在執行任何計算之前通過攝取所有資料來處理有界流。處理有界流不需要有序攝取,因為可以始終對有界資料集進行排序。有界流的處理也稱為批處理。

Apache Flink擅長處理無界和有界資料集。精确控制時間和狀态使Flink的運作時能夠在無界流上運作任何類型的應用程式。有界流由算法和資料結構内部處理,這些算法和資料結構專門針對固定大小的資料集而設計,進而産生出色的性能。
2.随處部署應用程式
Apache Flink是一個分布式系統,需要計算資源才能執行應用程式。Flink與所有常見的叢集資料總管(如Hadoop YARN,Apache Mesos和Kubernetes)內建,但也可以設定為作為獨立叢集運作。
Flink旨在很好地适用于之前列出的每個資料總管。這是通過特定于資料總管的部署模式實作的,這些模式允許Flink以其慣用的方式與每個資料總管進行互動。
部署Flink應用程式時,Flink會根據應用程式配置的并行性自動識别所需資源,并從資料總管請求它們。如果發生故障,Flink會通過請求新資源來替換發生故障的容器。送出或控制應用程式的所有通信都通過REST調用進行。這簡化了Flink在許多環境中的內建。
3.以任何比例運作應用程式
Flink旨在以任何規模運作有狀态流應用程式。應用程式可以并行化為數千個在叢集中分布和同時執行的任務。是以,應用程式可以利用幾乎無限量的CPU,主記憶體,磁盤和網絡IO。而且,Flink可以輕松維護非常大的應用程式狀态。其異步和增量檢查點算法確定對處理延遲的影響最小,同時保證一次性狀态一緻性。
使用者報告了在其生産環境中運作的Flink應用程式的可擴充性數字令人印象深刻,例如
- 應用程式每天處理數萬億個事件,
- 應用程式維護多個TB的狀态,以及
- 應用程式在數千個核心的運作。
4.利用記憶體中的性能
有狀态Flink應用程式針對本地狀态通路進行了優化。任務狀态始終保留在記憶體中,或者,如果狀态大小超過可用記憶體,則儲存在通路高效的磁盤上資料結構中。是以,任務通過通路本地(通常是記憶體中)狀态來執行所有計算,進而産生非常低的處理延遲。Flink通過定期和異步檢查本地狀态到持久存儲來保證在出現故障時的一次狀态一緻性。
5.Flink的架構
Flink 可以支援本地的快速疊代,以及一些環形的疊代任務。并且 Flink 可以定制化記憶體管理。在這點,如果要對比 Flink 和 Spark 的話,Flink 并沒有将記憶體完全交給應用層。這也是為什麼 Spark 相對于 Flink,更容易出現 OOM 的原因(out of memory)。就架構本身與應用場景來說,Flink 更相似與 Storm。如果之前了解過 Storm 或者 Flume 的讀者,可能會更容易了解 Flink 的架構和很多概念。下面讓我們先來看下 Flink 的架構圖。
我們可以了解到 Flink 幾個最基礎的概念,Client、JobManager 和 TaskManager。Client 用來送出任務給 JobManager,JobManager 分發任務給 TaskManager 去執行,然後 TaskManager 會心跳的彙報任務狀态。看到這裡,有的人應該已經有種回到 Hadoop 一代的錯覺。确實,從架構圖去看,JobManager 很像當年的 JobTracker,TaskManager 也很像當年的 TaskTracker。然而有一個最重要的差別就是 TaskManager 之間是是流(Stream)。其次,Hadoop 一代中,隻有 Map 和 Reduce 之間的 Shuffle,而對 Flink 而言,可能是很多級,并且在 TaskManager 内部和 TaskManager 之間都會有資料傳遞,而不像 Hadoop,是固定的 Map 到 Reduce。
三. Flink技術特點
1. 流處理特性
- 支援高吞吐、低延遲、高性能的流處理
- 支援帶有事件時間的視窗(Window)操作
- 支援有狀态計算的Exactly-once語義
- 支援高度靈活的視窗(Window)操作,支援基于time、count、session,以及data-driven的視窗操作
- 支援具有Backpressure功能的持續流模型
- 支援基于輕量級分布式快照(Snapshot)實作的容錯
- 一個運作時同時支援Batch on Streaming處理和Streaming處理
- Flink在JVM内部實作了自己的記憶體管理
- 支援疊代計算
- 支援程式自動優化:避免特定情況下Shuffle、排序等昂貴操作,中間結果有必要進行緩存
2. API支援
- 對Streaming資料類應用,提供DataStream API
- 對批處理類應用,提供DataSet API(支援Java/Scala)
3. Libraries支援
- 支援機器學習(FlinkML)
- 支援圖分析(Gelly)
- 支援關系資料處理(Table)
- 支援複雜事件處理(CEP)
4. 整合支援
- 支援Flink on YARN
- 支援HDFS
- 支援來自Kafka的輸入資料
- 支援Apache HBase
- 支援Hadoop程式
- 支援Tachyon
- 支援ElasticSearch
- 支援RabbitMQ
- 支援Apache Storm
- 支援S3
- 支援XtreemFS
5. Flink生态圈
Flink 首先支援了 Scala 和 Java 的 API,Python 也正在測試中。Flink 通過 Gelly 支援了圖操作,還有機器學習的 FlinkML。Table 是一種接口化的 SQL 支援,也就是 API 支援,而不是文本化的 SQL 解析和執行。對于完整的 Stack 我們可以參考下圖。
Flink 為了更廣泛的支援大資料的生态圈,其下也實作了很多 Connector 的子項目。最熟悉的,當然就是與 Hadoop HDFS 內建。其次,Flink 也宣布支援了 Tachyon、S3 以及 MapRFS。不過對于 Tachyon 以及 S3 的支援,都是通過 Hadoop HDFS 這層包裝實作的,也就是說要使用 Tachyon 和 S3,就必須有 Hadoop,而且要更改 Hadoop 的配置(core-site.xml)。如果浏覽 Flink 的代碼目錄,我們就會看到更多 Connector 項目,例如 Flume 和 Kafka。
四. Flink的程式設計模型
Flink提供不同級别的抽象來開發流/批處理應用程式。