Flink Exactly-once 實現原理解析

關注公衆號:大數據技術派,回覆"資料",領取1024G資料。

這一課時我們將講解 Flink “精確一次”的語義實現原理,同時這也是面試的必考點。

Flink 的“精確一次”處理語義是,Flink 提供了一個強大的語義保證,也就是說在任何情況下都能保證數據對應用產生的效果只有一次,不會多也不會少。

那麼 Flink 是如何實現“端到端的精確一次處理”語義的呢?

背景

通常情況下,流式計算系統都會爲用戶提供指定數據處理的可靠模式功能,用來表明在實際生產運行中會對數據處理做哪些保障。一般來說,流處理引擎通常爲用戶的應用程序提供三種數據處理語義:最多一次、至少一次和精確一次。

最多一次(At-most-Once):這種語義理解起來很簡單,用戶的數據只會被處理一次,不管成功還是失敗,不會重試也不會重發。

至少一次(At-least-Once):這種語義下,系統會保證數據或事件至少被處理一次。如果中間發生錯誤或者丟失,那麼會從源頭重新發送一條然後進入處理系統,所以同一個事件或者消息會被處理多次。

精確一次(Exactly-Once):表示每一條數據只會被精確地處理一次,不多也不少。

Exactly-Once 是 Flink、Spark 等流處理系統的核心特性之一,這種語義會保證每一條消息只被流處理系統處理一次。“精確一次” 語義是 Flink 1.4.0 版本引入的一個重要特性,而且,Flink 號稱支持“端到端的精確一次”語義。

在這裏我們解釋一下“端到端(End to End)的精確一次”,它指的是 Flink 應用從 Source 端開始到 Sink 端結束,數據必須經過的起始點和結束點。Flink 自身是無法保證外部系統“精確一次”語義的,所以 Flink 若要實現所謂“端到端(End to End)的精確一次”的要求,那麼外部系統必須支持“精確一次”語義;然後藉助 Flink 提供的分佈式快照和兩階段提交才能實現。

分佈式快照機制

我們在之前的課程中講解過 Flink 的容錯機制,Flink 提供了失敗恢復的容錯機制,而這個容錯機制的核心就是持續創建分佈式數據流的快照來實現。

同 Spark 相比,Spark 僅僅是針對 Driver 的故障恢復 Checkpoint。而 Flink 的快照可以到算子級別,並且對全局數據也可以做快照。Flink 的分佈式快照受到 Chandy-Lamport 分佈式快照算法啓發,同時進行了量身定做,有興趣的同學可以搜一下。

Barrier

Flink 分佈式快照的核心元素之一是 Barrier(數據柵欄),我們也可以把 Barrier 簡單地理解成一個標記,該標記是嚴格有序的,並且隨着數據流往下流動。每個 Barrier 都帶有自己的 ID,Barrier 極其輕量,並不會干擾正常的數據處理。

image.png

如上圖所示,假如我們有一個從左向右流動的數據流,Flink 會依次生成 snapshot 1、 snapshot 2、snapshot 3……Flink 中有一個專門的“協調者”負責收集每個 snapshot 的位置信息,這個“協調者”也是高可用的。

Barrier 會隨着正常數據繼續往下流動,每當遇到一個算子,算子會插入一個標識,這個標識的插入時間是上游所有的輸入流都接收到 snapshot n。與此同時,當我們的 sink 算子接收到所有上游流發送的 Barrier 時,那麼就表明這一批數據處理完畢,Flink 會向“協調者”發送確認消息,表明當前的 snapshot n 完成了。當所有的 sink 算子都確認這批數據成功處理後,那麼本次的 snapshot 被標識爲完成。

這裏就會有一個問題,因爲 Flink 運行在分佈式環境中,一個 operator 的上游會有很多流,每個流的 barrier n 到達的時間不一致怎麼辦?這裏 Flink 採取的措施是:快流等慢流。

image (1).png

拿上圖的 barrier n 來說,其中一個流到的早,其他的流到的比較晚。當第一個 barrier n到來後,當前的 operator 會繼續等待其他流的 barrier n。直到所有的barrier n 到來後,operator 纔會把所有的數據向下發送。

異步和增量

按照上面我們介紹的機制,每次在把快照存儲到我們的狀態後端時,如果是同步進行就會阻塞正常任務,從而引入延遲。因此 Flink 在做快照存儲時,可採用異步方式。

此外,由於 checkpoint 是一個全局狀態,用戶保存的狀態可能非常大,多數達 G 或者 T 級別。在這種情況下,checkpoint 的創建會非常慢,而且執行時佔用的資源也比較多,因此 Flink 提出了增量快照的概念。也就是說,每次都是進行的全量 checkpoint,是基於上次進行更新的。

兩階段提交

上面我們講解了基於 checkpoint 的快照操作,快照機制能夠保證作業出現 fail-over 後可以從最新的快照進行恢復,即分佈式快照機制可以保證 Flink 系統內部的“精確一次”處理。但是我們在實際生產系統中,Flink 會對接各種各樣的外部系統,比如 Kafka、HDFS 等,一旦 Flink 作業出現失敗,作業會重新消費舊數據,這時候就會出現重新消費的情況,也就是重複消費。

針對這種情況,Flink 1.4 版本引入了一個很重要的功能:兩階段提交,也就是 TwoPhaseCommitSinkFunction。兩階段搭配特定的 source 和 sink(特別是 0.11 版本 Kafka)使得“精確一次處理語義”成爲可能。

在 Flink 中兩階段提交的實現方法被封裝到了 TwoPhaseCommitSinkFunction 這個抽象類中,我們只需要實現其中的beginTransaction、preCommit、commit、abort 四個方法就可以實現“精確一次”的處理語義,實現的方式我們可以在官網中查到:

  1. beginTransaction,在開啓事務之前,我們在目標文件系統的臨時目錄中創建一個臨時文件,後面在處理數據時將數據寫入此文件;
  2. preCommit,在預提交階段,刷寫(flush)文件,然後關閉文件,之後就不能寫入到文件了,我們還將爲屬於下一個檢查點的任何後續寫入啓動新事務;
  3. commit,在提交階段,我們將預提交的文件原子性移動到真正的目標目錄中,請注意,這會增加輸出數據可見性的延遲;
    abort,在中止階段,我們刪除臨時文件。

image (2).png

如上圖所示,我們用 Kafka-Flink-Kafka 這個案例來介紹一下實現“端到端精確一次”語義的過程,整個過程包括:

  • 從 Kafka 讀取數據
  • 窗口聚合操作
  • 將數據寫回 Kafka

整個過程可以總結爲下面四個階段:

  1. 一旦 Flink 開始做 checkpoint 操作,那麼就會進入 pre-commit 階段,同時 Flink JobManager 會將檢查點 Barrier 注入數據流中 ;
  2. 當所有的 barrier 在算子中成功進行一遍傳遞,並完成快照後,則 pre-commit 階段完成;
  3. 等所有的算子完成“預提交”,就會發起一個“提交”動作,但是任何一個“預提交”失敗都會導致 Flink 回滾到最近的 checkpoint;
  4. pre-commit 完成,必須要確保 commit 也要成功,上圖中的 Sink Operators 和 Kafka Sink 會共同來保證。

現狀

目前 Flink 支持的精確一次 Source 列表如下表所示,你可以使用對應的 connector 來實現對應的語義要求:

數據源 語義保證 備註
Apache Kafka exactly once 需要對應的 Kafka 版本
AWS Kinesis Streams exactly once
RabbitMQ at most once (v 0.10) / exactly once (v 1.0)
Twitter Streaming API at most once
Collections exactly once
Files exactly once
Sockets at most once

如果你需要實現真正的“端到端精確一次語義”,則需要 sink 的配合。目前 Flink 支持的列表如下表所示:

寫入目標 語義保證 備註
HDFS rolling sink exactly once 依賴 Hadoop 版本
Elasticsearch at least once
Kafka producer at least once / exactly once 需要 Kafka 0.11 及以上
Cassandra sink at least once / exactly once 冪等更新
AWS Kinesis Streams at least once
File sinks at least once
Socket sinks at least once
Standard output at least once
Redis sink at least once

總結

由於強大的異步快照機制和兩階段提交,Flink 實現了“端到端的精確一次語義”,在特定的業務場景下十分重要,我們在進行業務開發需要語義保證時,要十分熟悉目前 Flink 支持的語義特性。

這一課時的內容較爲晦澀,建議你從源碼中去看一下具體的實現。

猜你喜歡
Spark SQL知識點與實戰
Hive計算最大連續登陸天數
Hadoop 數據遷移用法詳解
數倉建模分層理論
數倉建模—寬表的設計

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