從淺入深理解流式計算框架Flink

隨着互聯網的不斷髮展,行業內對於數據的處理能力和計算的實時性要求都在不斷增加,隨之而來的是計算框架的升級。經過了十餘年開源社區的不斷演進,現在計算框架已經從第一代的雅虎開源的Hadoop體系進化到目前主流的Spark框架,這兩套框架的計算主要是從強依賴硬盤存儲能力的計算髮展到了內存計算,大大增強了計算力。下一代計算引擎,也就是第三代計算引擎,將會從計算實時性的角度突破,也就是今天要講到的Flink框架,本文將從簡入深的介紹Flink框架的特點。

基本架構

 

調度層面Flink支持本地運行以及分佈式運行兩種,分佈式運行可以跑在目前主流的基於Yarn體系中,也可以跑在目前業內最主流的K8S中,Flink本質上還是專注於做計算框架的部分,應用於目前行業內主流的調度引擎上而確保一個分佈式的計算能力。

 

在覈心層主要做的是一件事是如何對流式任務進行編排,流式任務不同於離線任務的最大一個特點在於任務編排上面,比如我們有三個事件分別叫1、2、3。在離線任務中,事件運行是有先後順序的,比如要先運行1再運行2接着運行3,在流式任務場景下這種事件只有邏輯上的先後關係,實際上是同時觸發並執行的。

 

API層面稍後單獨用一個模塊講解,在Library方面內置了圖計算算法包Gelly和機器學習包FlinkML以及CEP。其中Gelly和FlinkML是基於DataSet API進行開發的,而DataSet API是一個離線批計算的接口,所以本質上Gelly和FlinkML並沒有發揮Flink這個天然流式框架的優勢。個人覺得,Flink作爲Apache相對比較年輕的開源計算框架,對於一些組件化的支持還不完善,相比於Spark生態還有比較大的差距。後續如果能基於Flink Stream API開發出流式的上層應用,會成爲Flink的一大亮點。

 

分佈式架構層面Flink和Spark或者Hadoop區別不大,整體框架是:

由Flink的Client向Job Master提交任務,Job Master作爲整個集羣的管理節點。Task Manager是Slave的角色,負責底層的運算工作。Job Master控制整個計算任務的Checkpoint的進度。Task Manager間可以通過數據流的方式交換數據,同時Task Manager在任務的並行化計算方面比MapReduce做的更好,Flink Task Manager是採用多線程的機制進行並行化數據計算,而傳統的MapReduce方法採用的是JVM進程的形式。

開發接口架構

作爲一個算法發燒友,我還是願意花更多的篇幅來介紹如何基於Flink框架進行開發。首先看下開放編程接口的API上下游站位關係,

 

最上一層是Flink SQL,這一層其實是一個上級封裝,瞭解機器學習或者其它更復雜編程模型的同學應該比較清楚,並不是所有的邏輯都能通過SQL來實現。不過目前絕大部分的數據實時處理邏輯通過SQL這一層就可以解決。

 

TableAPI這一級可以看出Flink要實現流批一體化的野心,Flink希望可以在流式DataStream API和離線DataSet API之上做一層封裝,對用戶暴露更多複雜計算的函數,同時基於這一層API實現的功能可以完成流批一體。這個設想是很好的,不過目前還有很多功能沒辦法在這一級實現,也導致了TableAPI的尷尬。

 

DataStream和DataSet仍是目前的主流編程接口,如果希望在Flink中實現諸如機器學習算法這樣負責邏輯的函數,還是要依賴於這一層。至於Runtime內核開發,這個明顯是留給非常資深的高級用戶來使用,大部分的開發應該不會觸碰。

 

如何做流式編程

 

重點講下DataStream這個開發接口,首先Flink把流式編程模型切分爲DataSource模塊、Transformation模塊和DataSink模塊。DataSource和DataSink分別對應着數據的流入和流出。

 

在DataSource和Sink模塊,Flink都原生支持了Apache體系內的很多產品的I/O,比如Kafka Connector和Elastic Search Connector等等。同時在數據接入導出方面還內置了很多數據源,

  • readFile接口可以實現讀寫一些CSV、TXT本地文件

  • Socket數據源可以接收來自其它服務的數據,這個接口非常好,可以讓Flink和許多主流的Restful服務適配

 

在Transformation模塊,DataStream提供了諸如map、FlatMap、Filter、Reduce、KeyBy這些函數,我個人感覺Flink的這些接口使用起來還是比較方便的,比如要把下面這個二元組類型的數據都+1,

(a,1),(b,2)->(a,2),(b,3)

 

只需要使用map函數作如下處理:

 

val dataStream=env.fromElements((a,1),(b,2))

val mapStream:DataStream[(String,Int)]= dataStream.map(t=>(t._1,t._2+1))

 

流式編程的時間概念與Watermark

流式開發和離線開發的最大區別在於對於數據時間的理解上,離線開發針對的都是有邊界數據,有邊界的意思是在開發過程中會用到的數據是有限的。而流式應用,因爲數據是實時流入的,所以對應的數據是無邊界的。以機器學習算法爲例,經常需要緩衝一部分數據求區間內的最大值和最小值,那麼在無邊界數據條件下如何處理呢?這裏就應用到了watermark功能。

 

首先介紹下幾個時間的概念:

  • Event Time是數據在業務方的真實發生時間,比如某個手機在2019-03-05下午2點被購買,這個時間就是Event Time

  • Ingestion Time指的是數據進入Flink系統的時間,理論上會比Event Time晚一點

  • Processing Time:數據在當前系統被處理的時間,也就是Flink worker機器的時間,這個是Flink系統的默認時間

所以從概念層面理解,用Flink去處理業務最合適的時間是Event Time,而系統默認使用Processing Time是一種簡化方法,因爲流式數據在錄入Flink系統的過程中會出現時間亂序。

 

接着介紹下Window和Watermark的概念,當系統按照Processing Time去流式處理數據的時候,假設某個流式算法需要緩衝5分鐘的數據算一次Loss,這個5分鐘就是一個Window窗口。但是當5分鐘已經結束了,還是沒有數據流入計算引擎,這個時候怎麼辦?接着等還是執行下一個操作。這就用到了Watermark,當等待時間超過Watermark的設定時間,系統就會自動觸發計算,無論數據是否滿足Window的要求。

寫到做後

本文是我學習了Flink的一些資料之後的筆記,可以作爲對Flink框架的一個大體瞭解。其實隨着互聯網業務的不斷髮展和計算框架的普及,後續各種廣告推薦、商品推薦、金融風控相關的業務都會逐漸從傳統的離線計算向流式計算轉型。未來Flink在數據業務領域大有可爲,期待接下來產業計算的框架升級。

 

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