1. 程式人生 > 其它 >Flink 流處理

Flink 流處理

Apache Flink可實現可擴充套件並行度的 ETL、資料分析以及事件驅動的流式應用程式。


Flink API中的狀態管理和時間介紹具體內容如下:

  • 如何實現流資料處理管道(pipelines)
  • Flink 如何管理狀態以及為何需要管理狀態
  • 如何使用事件時間(event time)來一致並準確地進行計算分析
  • 如何在源源不斷的資料流上構建事件驅動的應用程式
  • Flink 如何提供具有精確一次(exactly-once)計算語義的可容錯、有狀態流處理

四個重要概念:

  • 源源不斷的流式資料處理
  • 事件時間
  • 有狀態流處理
  • 狀態快照

流處理

在自然環境中,資料的產生原本就是流式的

無論是來自 Web 伺服器的事件資料,證券交易所的交易資料,還是來自工廠車間機器上的感測器資料,其資料都是流式

的。

但是當你分析資料時,可以圍繞有界流bounded)或無界流unbounded)兩種模型來組織處理資料,當然,選擇不同的模型,程式的執行和處理方式也都會不同。

批處理:是有界資料流處理的範例。在這種模式下,你可以選擇在計算結果輸出之前輸入整個資料集,這也就意味著你可以對整個資料集的資料進行排序、統計或彙總計算後再輸出結果。

流處理:正相反,其涉及無界資料流。至少理論上來說,它的資料輸入永遠不會結束,因此程式必須持續不斷地對到達的資料進行處理。

在 Flink 中,應用程式由使用者自定義運算元轉換而來的流式 dataflows所組成。這些流式 dataflows 形成了有向圖,以一個或多個

(source)開始,並以一個或多個(sink)結束。

通常,程式程式碼中的transformationdataflow中的運算元(operator)之間是一一對應的。但有時也會出現一個 transformation 包含多個運算元的情況,如上圖所示。

Flink 應用程式可以消費來自訊息佇列分散式日誌這類流式資料來源(例如 Apache Kafka 或 Kinesis)的實時資料,也可以從各種的資料來源中消費有界的歷史資料。同樣,Flink 應用程式生成的結果流也可以傳送到各種資料匯中。

並行 Dataflows

Flink 程式本質上是分散式並行程式。在程式執行期間:

  • 一個流有一個或多個流分割槽
    (Stream Partition)
  • 每個運算元有一個或多個運算元子任務(Operator Subtask)。

每個子任務彼此獨立,並在不同的執行緒中執行,或在不同的計算機或容器中執行。

運算元子任務數就是其對應運算元的並行度。在同一程式中,不同運算元也可能具有不同的並行度。

Flink 運算元之間可以通過一對一直傳)模式或重新分發模式傳輸資料:

  • 一對一模式

例如上圖中的Sourcemap()運算元之間可以保留元素的分割槽和順序資訊。

這意味著map()運算元的 subtask[1] 輸入的資料以及其順序與Source運算元的 subtask[1] 輸出的資料和順序完全相同,即同一分割槽的資料只會進入到下游運算元的同一分割槽。

  • 重新分發模式

例如上圖中的map()keyBy/window之間,以及keyBy/windowSink之間則會更改資料所在的流分割槽。

當你在程式中選擇使用不同的transformation,每個運算元子任務也會根據不同的 transformation 將資料傳送到不同的目標子任務。

例如以下這幾種 transformation 和其對應分發資料的模式:

  • keyBy()(通過雜湊鍵重新分割槽)
  • broadcast()(廣播)
  • rebalance()(隨機重新分發)。

重新分發資料的過程中,元素只有在每對輸出和輸入子任務之間才能保留其之間的順序資訊(例如,keyBy/window的 subtask[2] 接收到的map()的 subtask[1] 中的元素都是有序的)。

因此,上圖所示的keyBy/windowSink運算元之間資料的重新分發時,不同鍵(key)的聚合結果到達 Sink 的順序是不確定的

自定義時間流處理

對於大多數流資料處理應用程式而言,能夠使用處理實時資料的程式碼重新處理歷史資料併產生確定並一致的結果非常有價值。

在處理流式資料時,我們通常更需要關注事件本身發生的順序而不是事件被傳輸以及處理的順序,因為這能夠幫助我們推理出一組事件(事件集合)是何時發生以及結束的。

例如電子商務交易或金融交易中涉及到的事件集合。

為了滿足上述這類的實時流處理場景,我們通常會使用記錄在資料流中的事件時間的時間戳,而不是處理資料的機器時鐘的時間戳。

有狀態流處理

Flink 中的運算元可以是有狀態的。

這意味著如何處理一個事件可能取決於該事件之前所有事件資料的累積結果。Flink 中的狀態不僅可以用於簡單的場景(例如統計儀表板上每分鐘顯示的資料),也可以用於複雜的場景(例如訓練作弊檢測模型)。

Flink 應用程式可以在分散式群集上並行執行,其中每個運算元的各個並行例項會在單獨的執行緒中獨立執行,並且通常情況下是會在不同的機器上執行。

有狀態運算元的並行例項組在儲存其對應狀態時通常是按照鍵(key)進行分片儲存的。每個並行例項運算元負責處理一組特定鍵的事件資料,並且這組鍵對應的狀態會儲存在本地

如下圖的 Flink 作業,其前三個運算元的並行度為 2最後一個 sink 運算元的並行度為 1,其中第三個運算元是有狀態的,並且你可以看到第二個運算元和第三個運算元之間是全互聯的(fully-connected),它們之間通過網路進行資料分發。

通常情況下,實現這種型別的 Flink 程式是為了通過某些鍵對資料流進行分割槽,以便將需要一起處理的事件進行匯合,然後做統一計算處理。

Flink 應用程式的狀態訪問都在本地進行,因為這有助於其提高吞吐量和降低延遲。通常情況下 Flink 應用程式都是將狀態儲存在JVM 堆上,但如果狀態太大,我們也可以選擇將其以結構化資料格式儲存在高速磁碟中。

通過狀態快照實現的容錯

通過狀態快照流重放兩種方式的組合,Flink 能夠提供可容錯的,精確一次計算的語義。

這些狀態快照在執行時會獲取並存儲分散式 pipeline 中整體的狀態,它會將資料來源中消費資料的偏移量記錄下來,並將整個job graph中運算元獲取到該資料(記錄的偏移量對應的資料)時的狀態記錄並存儲下來。

當發生故障時,Flink 作業會恢復上次儲存的狀態,重置資料來源從狀態中記錄的上次消費的偏移量開始重新進行消費處理。而且狀態快照在執行時會非同步獲取狀態並存儲,並不會阻塞正在進行的資料處理邏輯。