Flink基於RocksDB的增量檢查點機制

Flink之所以能夠做到高效而準確的有狀態流式處理,核心是依賴於檢查點(checkpoint)機制。當流式程序運行出現異常時,能夠從最近的一個檢查點恢復,從而最大限度地保證數據不丟失也不重複。

Flink檢查點本質上是通過異步屏障快照(asychronous barrier snapshot, ABS)算法產生的全局狀態快照,一般是存儲在分佈式文件系統(如HDFS)上。但是,如果狀態空間超大(比如key非常多或者窗口區間很長),檢查點數據可能會達到GB甚至TB級別,每次做checkpoint都會非常耗時。由於狀態數據在檢查點之間的變化往往沒有那麼明顯,增量檢查點可以很好地解決這個問題。顧名思義,增量檢查點只包含本次checkpoint與上次checkpoint狀態之間的差異,而不是所有狀態,變得更加輕量級了。

目前Flink有3種狀態後端,即內存(MemoryStateBackend)、文件系統(FsStateBackend)和RocksDB(RocksDBStateBackend),只有RocksDB狀態後端支持增量檢查點。該功能默認關閉,要打開它可以在flink-conf.yaml中配置:

 

state.backend: rocksdb
state.backend.incremental: true

或者在代碼中配置:

 

RocksDBStateBackend rocksDBStateBackend = new RocksDBStateBackend("hdfs://path/to/flink-checkpoints", true);
env.setStateBackend(rocksDBStateBackend);

爲什麼只有RocksDB狀態後端支持增量檢查點呢?這是由RocksDB本身的特性決定的。RocksDB是一個基於日誌結構合併樹(LSM樹)的鍵值式存儲引擎,我們能明確地感覺到,它與HBase肯定有諸多相似之處。如果看官不瞭解LSM樹的話,可以通過這篇文章來做個簡單的瞭解。

在RocksDB中,扮演HBase MemStore角色的寫緩存叫做memtable。memtable寫滿之後也會flush到磁盤,形成與HFile類似的東西,叫做sstable(是“有序序列表”即sorted sequence table的縮寫)。RocksDB也存在compaction線程,在後臺合併已經寫入的sstable,原有的sstable會包含所有的鍵值對,合併前的sstable在此後會被刪除。

由於Flink檢查點生成的時間必須確定,因此不能等待RocksDB的memtable自動flush到磁盤,而是由Flink主動調用RocksDB提供的API強制刷寫。有了上面的鋪墊,下面通過例子來解釋增量檢查點的過程。

From https://flink.apache.org/features/2018/01/30/incremental-checkpointing.html

上圖示出一個有狀態的算子的4個檢查點,其ID爲2,並且state.checkpoints.num-retained參數設爲2,表示保留2個檢查點。表格中的4列分別表示RocksDB中的sstable文件,sstable文件與存儲系統中文件路徑的映射,sstable文件的引用計數,以及保留的檢查點的範圍。

下面按部就班地解釋一下:

  1. 檢查點CP 1完成後,產生了兩個sstable文件,即sstable-(1)與sstable-(2)。這兩個文件會寫到持久化存儲(如HDFS),並將它們的引用計數記爲1。
  2. 檢查點CP 2完成後,新增了兩個sstable文件,即sstable-(3)與sstable-(4),這兩個文件的引用計數記爲1。並且由於我們要保留2個檢查點,所以上一步CP 1產生的兩個文件也要算在CP 2內,故sstable-(1)與sstable-(2)的引用計數會加1,變成2。
  3. 檢查點CP 3完成後,RocksDB的compaction線程將sstable-(1)、sstable-(2)、sstable-(3)三個文件合併成了一個文件sstable-(1,2,3)。CP 2產生的sstable-(4)得以保留,引用計數變爲2,並且又產生了新的sstable-(5)文件。注意此時CP 1已經過期,所以sstable-(1)、sstable-(2)兩個文件不會再被引用,引用計數減1。
  4. 檢查點CP 4完成後,RocksDB的compaction線程將sstable-(4)、sstable-(5)以及新生成的sstable-(6)三個文件合併成了sstable-(4,5,6),並對sstable-(1,2,3)、sstable-(4,5,6)引用加1。由於CP 2也過期了,所以sstable-([1~4])四個文件的引用計數同時減1,這就造成sstable-(1)、sstable-(2)、sstable-(3)的引用計數變爲0,Flink就從存儲系統中刪除掉這三個文件。

通過上面的分析,我們可以看出Flink增量檢查點機制的巧妙之處:

  • 通過跟蹤sstable的新增和刪除,可以記錄狀態數據的變化;
  • 通過引用計數的方式,上一個檢查點中已經存在的文件可以直接被引用,不被引用的文件可以及時刪除;
  • 可以保證當前有效的檢查點都不引用已經刪除的文件,從而保留state.checkpoints.num-retained參數指定的狀態歷史。

增量檢查點解決了大狀態checkpointing的問題,但是在從檢查點恢復現場時會帶來潛在的overhead。這是顯然的:當程序出問題後,TaskManager需要從多個檢查點中加載狀態數據,並且這些數據中還可能會包含將被刪除的狀態。還有一點,就算磁盤空間緊張,舊檢查點的文件也不能隨便刪除,因爲新檢查點仍然會引用它們,如果貿然刪除,程序就無法恢復現場了。可見,優秀的技術方案往往也不是十全十美,往往都是要考慮tradeoff的。


 

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