摘要:本文整理自 Apache Flink Contributor 俞航翔 9 月 24 日在 Apache Flink Meetup 的演講。主要內容包括:
- Checkpoint 效能最佳化之路
- 解析 Changelog
- 一覽 State/Checkpoint 最佳化
一、Checkpoint 效能最佳化之路
Flink 作為一個 Stateful 計算引擎,State 是其非常重要的概念,它支援 Stateful 運算元透過 State 記錄多個 Events 之間的資訊,並在 Checkpoint 時做狀態持久化,儲存全域性一致性快照,在恢復時透過 Resume Checkpoint 以及 Replay 來實現不同語義的一致性保障。
容錯是長期執行的流式系統非常重要的部分,而 Checkpoint 的主要目的就是解決 Failover 問題。基於此目標,它的生命週期完全由 Flink 管理。因此對於不同的 StateBackend 可以用特定的原生格式進行儲存,利用 StateBackend 的內部機制比如 Incremental Checkpoint 做進一步最佳化等。
基於以上機制, Checkpoint 目前的設計目標就是更輕量以及更快速的恢復。
那 Flink 在 Chekpoint 效能上做了哪些最佳化呢?
最早期,在支援輕量級非同步 Snapshot 演算法後, Flink Checkpoint 的效能往前邁了一大步。在該機制下,Flink 將 Barrier 作為特殊 Record 在 Graph 中流動,同時將耗時較大的檔案上傳等工作放到非同步過程中進行,極大降低了對主流程的影響。
在 1.0 版本中,Flink 開始支援 RocksDB StateBackend ,這對大狀態下的儲存提供了很好的支援。1.3 版本 Flink實現了基於 RocksDB Incremental Checkpoint 的機制,進一步提升了Checkpoint 在非同步階段的效能。1.11 版本 Flink 引入了 Unaligned Checkpoint,並在 1.13 版本達到了 Production-ready 狀態,對於 Barrier 對齊有瓶頸的作業,這個技術讓作業在反壓比較嚴重的情況下依然可以做出 Checkpoint 。1.14 版本引入的 Buffer Debloating 可以透過動態調整 Network Buffer 大小來加速 Barrier 流動,進一步加速 Aligned Checkpoint 完成,減少 Unaligned Checkpoint 儲存的資料量。1.15 和 1.16 中 Flink 引入了 Changelog StateBackend ,它透過更通用的 Incremental Checkpoint 機制進一步提升了 Checkpoint 的非同步效能。
我們可以透過這張圖來看一下這些技術在作業執行鏈路中的作用。
當 Checkpoint 觸發時, Barrier 會隨著 Graph 流動。當開啟 Buffer Debloating 後,Flink 會透過計算吞吐等方式動態調整 Network Buffer 的大小來加速 Barrier 傳遞。當 Barrier 到達 Stateful 節點時,如果是 Aligned Checkpoint ,則運算元會等待 Barrier 對齊再觸發後續的 Checkpoint 行為;如果是 Unaligned Checkpoint ,則會直接將 Barrier 傳遞給後續運算元,同時觸發 StateBackend 上的 Checkpoint,並將 Buffer 中的內容儲存到 HDFS ,不會阻塞,如圖中間的實線所示。
在 StateBackend 內部觸發 Checkpoint 時,基於非同步 Checkpoint 演算法,非同步部分會進行檔案上傳,如圖中實線所示。而在開啟了 RocksDB Incremental Checkpoint 時,會做增量檔案上傳,如上圖中,只有更新後的 S2、S4 需要上傳到遠端。
Changelog StateBackend 的核心機制如上圖最下方虛線所示,會將原先的 StateBackend 非同步上傳和 Changelog 部分進行解耦,引入了額外獨立上傳到 HDFS 的過程,這個過程將穩定、持續地發生在作業執行過程中。
我們可以透過 Checkpoint Metrics 相關資訊來直觀感受下這些技術的作用。
Metrics 上關於 Size 的關鍵指標有 Checkpointed DataSize 和 Full Checkpoint DataSize 兩個,是 1.15 版本在 Flink UI 中透出的指標,我們可以透過這兩個指標直接看出增量 Checkpoint 的效能以及儲存在遠端的空間大小。
剩餘的指標主要是關於耗時的,StartDelay 指標過大通常是因為作業反壓,一般需要先排查作業邏輯。此外,StartDelay 過大時,如果作業邏輯允許,可開啟 Unaligned Checkpoint 和 Buffer Debloating 以加速 Checkpoint 完成。如果 Aligned Duration 指標比較長,可以考慮開啟 Unaligned Checkpoint 。
同步 Duration 和非同步 Duration 是整個 Checkpoint 是我們通常最關注的兩個部分,而非同步部分的耗時通常是最常見的瓶頸點。非同步部分的最佳化可以透過開啟 Incremental Checkpoint 以減少非同步上傳量,或者透過開啟 Changelog StateBackend 來進一步縮短非同步耗時。
二、解析 Changelog
Changelog 的核心目標如下:
- 更穩定的 Checkpoint:透過解耦 Compaction 和 Checkpoint 過程,使 Checkpoint 更穩定,大幅減少 Checkpoint Duration 突增的情況,還可進一步減少 CPU 抖動,使網路頻寬變得更平穩。
在大規模、大狀態作業上經常會出現 CPU 隨著 Checkpoint 週期性抖動,進而影響作業和叢集穩定性的情況。Changelog 透過解耦 Checkpoint 觸發 Compaction 的過程,可以使 CPU 變得更平穩。另外,在非同步過程中,Compaction 導致的大量檔案同時上傳有時會將網路頻寬打滿, 而 Changelog 是能夠緩解該狀況的。
- 更快速的 Checkpoint:Checkpoint 期間會上傳相對固定的增量,可以達到秒級完成 Checkpoint 的目標。
- 更小的端到端延遲:Flink 中實現端到端的 Exactly-once 語義主要依賴於 Checkpoint 的完成時間。Checkpoint 完成越快,Transactional sink 可以提交得更頻繁,保證更好的資料新鮮度。後續可與 Table Store 結合,保證 Table Store 上的資料更新鮮。
- 更少的資料回追:透過設定更小的 Checkpoint Interval 加速 Failover 過程,可以減少資料回追。
雖然目前 Changelog 的機制下,Restore 時在 TM 上會有額外的 Replay 時間開銷,但總體來看,耗費的時間還是相對減少的。
那 RocksDB Incremental Checkpoint 為什麼做不到快速且穩定呢?
我們先看下 RocksDB 的訪問機制:當一條 Record 寫到 RocksDB 時,首先會寫到 Memtable ,資料量達到 Memtable 閾值後會 Memtable 變為 Immutable Memtable;當資料量再達到整個 Memory 所有 Memtable 的閾值後,會 Flush 到磁碟,形成 SST Files 。L0 的 SST files 之間是有 Overlap 的 。Flink 預設使用 RocksDB 的 Level Compaction 機制 ,因此在 L0 達到閾值後,會繼續觸發 Level Compaction,與 L1 進行 Compaction ,進一步可能觸發後續 Level Compaction。
我們再來看一下 Checkpoint 同步階段和非同步階段做了些什麼。在同步過程中,Checkpoint 首先會觸發 Memtable 強制 Flush,這一過程可能會觸發後面級聯的 Level Compaction,該步驟可能導致大量檔案需要重新上傳。同時,同步過程中會做 Local Checkpoint ,這是 RocksDB 本地的 Checkpoint 機制,對 Rocksdb 而言其實就是 Hard Link 一些 SST Files,是相對輕量的。非同步過程會將這些 SST Files 上傳,同時寫入 Meta 資訊。
我們可以看到兩個重要部分:
- 資料量達到閾值,或者 cp 的同步階段,是會觸發 Memtable Flush,進一步觸發級聯 Level Compation,進一步導致大量檔案需要重新上傳的
- 在大規模作業中,每次 Checkpoint 可能都會因為某一個 Subtask 非同步時間過長而需要重新上傳很多檔案。端到端 Duration 會因為 Compaction 機制而變得很長。
那麼 Changelog 做了什麼改進呢?
在介紹 Changelog 的機制之前,我先介紹下幾個內部的術語
State Table 是本地狀態資料讀寫結構,比如 RocksDB。我們更傾向於將 Changelog 理解為 StateBackend 上的功能增強,已有的 StateBackend(HashmapStateBackend/RocksDBStateBackend,或者自定義的一種StateBackend)均可以開啟該功能 。而且我們在 1.16 中實現了 Changelog 開到關和關到開的相容性,使用者可以非常方便地在存量作業中使用。
Materialization 是 State Table 持久化的過程,可以理解為 RocksDBStateBackend 或 HashmapStateBackend 做 Checkpoint 的過程。目前會定時觸發,完成一次成功的 Materialization 後會 Truncate 掉 Changelog ,即做 Changelog 的清理。
DSTL 是 Changelog 的儲存元件。Changelog 的寫入需要提供持久化、低延遲、一致性及併發支援。目前基於 DFS 實現了 DSTL,後續我們將繼續探索其他實現方式。
Changelog 的機制很像 WAL 的機制。
如圖所示,圖中下面部分為 State Table ,上面為 Changelog 的儲存部分即 DSTL 。
首先,在狀態寫入時,會同時寫到 State Table 和 DSTL,如果 State Table 是 Rocksdb,那麼它的後續流程就像我們剛才提到的一樣,包括寫 Memtable,Flush,觸發 Compaction 等等過程。DSTL 這個部分會以操作日誌的方式追加寫入 DSTL,我們也支援了不同 State 型別的各種操作的寫入。
其中 DSTL 會有一套完整的定時持久化機制持久化到遠端儲存中,所有 Changelog 將會在執行過程中連續上傳,同時在 Checkpoint 上傳較小的增量。
State Table 會定時進行 Materialization,在完成一次完整的 Materialization 後將會對 Changelog 進行 Truncate,清理掉失效的 Changelog,然後新的 Checkpoint 將以這個 Materialization 為基準繼續持續上傳增量。
我們按讀寫流程、Checkpoint 流程、Restore 流程再總結下這個過程。
在狀態寫入時,會雙寫到 State Table 和 Dstl,讀取時會從 State Table 中讀取,即讀寫鏈路上只是多了個雙寫,且 Dstl 的部分是 append-only 的寫入,會非常輕量級。
在 Checkpoint 時,依賴於定時 Materilize State Table,以及定期 Persist Changelog,需要上傳的增量會非常小,在上傳小增量後只需要把 Materialization 部分的 Handle 和 Changelog 部分的 Handle 組合返回給 jm 即可。同時我們也會依賴於 Truncate 機制去及時清理無效 Changelog。
在 Restore 時,我們拿到了 State Table 的 Handle 和 Changelog 的 Handle,State Table 部分會按之前的方式進行 Retsore,比如是 Rocksdb,那麼在沒開啟 Local Recovery 時,會先下載遠端 SST Files,再 Rebuild。Changelog 部分再沒有開啟 Local Recovery 時,會先下載遠端 State Change,然後重新 Apply 到 State Table,Rebuild Changelog 部分。
Changelog 開啟後,Checkpoint 檔案上傳過程會變得非常平滑。此前,只有在 Checkpoint 時才會上傳檔案;而現在有了 Materialization 以及定期做 Changelog 增量上傳,實際做 Checkpoint 時需要上傳的增量變得非常小。
上圖為相關常用引數的含義和使用方法。
Changelog 能夠使 Checkpoint 更快速以及更穩定,但是會存在三個額外開銷:
- 額外的儲存空間。Truncate 之前,State Changelog 會一直佔用額外的儲存空間。
- 額外的恢復開銷。Restore 過程需要額外 Apply 以及額外下載,因此也需要額外的恢復,恢復過程會佔用耗時。
- 額外的效能開銷。State Changelog 會做定時上傳,存在一定的效能開銷。
我們基於 RocksDB incremental 與 Changelog 做了 Benchmark 。Changelog 下使用的 State Table 為 RocksDB,開啟 Incremental ,使用 OSS 作為儲存介質;將 Checkpoint Interval 設定為 1 秒,對 RocksDB 而言意味著儘可能快地執行 Checkpoint ;將 Materialization Interval 設定為 3 分鐘,Source Rate 設定為 10k/s,該速率對於兩者而言都是比較日常的流量。
結果顯示,RocksDB 側 Duration 不穩定,時少時多。Checkpoint Datasize 存在週期性特徵,每隔 4 個會增加,這是由於 Checkpoint 期間會 Flush Memtable 觸發 Compaction 導致,且 RocksDB 配置 L0 的閾值為 4。而 Changelog 部分執行很穩定。
上圖展示了 Checkpoint Duration 情況,我們擷取了 P99 的資料做了兩組引數,主要針對不同單併發 State Size 。結果顯示,CP 端到端的延時,Changelog 可以在 1s 以內完成,RocksDB 延遲約 17 秒。
大 State 在 1GB 單併發場景下,空間開銷約為 1.2-1.5 倍。在記憶體中會更多一些,因為 RocksDB 在記憶體中資料會變得更緊緻。
實際測試中,Sliding Window 場景下的空間消耗會更明顯,可能會超出兩倍。因為 Sliding Window 時,每個 Windows 之間 State 不共享,會儲存多份。另外,Sliding Window 在 Checkpoint 期間會不斷觸發 Purge 操作,Sliding Size 設定越小,Purge 越多,RocksDB 相對能更好地合併 Push 操作。另外,因為 Changelog 使用了操作日誌方式儲存,Truncate 比較慢,部分全量會放得很大。
針對於 Sliding Window 的最佳化也一直在討論中,比如支援 Changelog 之間的 Merge 方式。目前機制下,是否啟用 Changelog 是空間放大與 Checkpoint 穩定性和更快速度之間的取捨。目前雲上的空間相對廉價,因此在大多數情況下,犧牲空間換取效能和穩定性的方案是可以接受的。
將 Local Recovery 關閉後,RocksDB 與 Changelog 之間存在 9 秒的時間差。結合 Local Recovery 功能將 download 部分的差距抹掉,最終時間差距為 3 秒左右。在極限 TPS 上,Changelog 會有 10% 的損耗。測試時將整個 Benchmark 打滿,打到反壓後測試其極限狀態。後續我們將針對 DSTL 上傳部分做最佳化。
值得注意的是,這裡測試的是極限情況。日常情況下,兩者的 TPS 效能相差不多,甚至 Changelog 更優。因為在 同樣的 Interval 設定下, RocksDB Compaction 會變得更頻繁。
未來,我們的最佳化方向主要包含以下三個:
- 第一,減少空間消耗,以及最佳化極限 TPS 場景。
- 第二,結合 Failover 2.0,使 Checkpoint 做得更快、使 Recovery 變得更快以及實現 Reactive Mode 功能。因為在 Reactive Mode 下,增加了資源後會依賴於該機制做 Failover 後重啟。如果能夠將 Checkpoint 做得更快,狀態恢復也會變得更快。
- 第三,讓 Table Store 獲得更好的資料新鮮度。
三、 一覽 State/Checkpoint 最佳化
1.16 版本在 State 和 Checkpoint 方面也做了不少最佳化。
可用性方面,做了針對於 RocksDB 監控和可用性的提升,匯出了 Database Level 監控。同時也提高了 Unaligned Checkpoint 和 Aligned Checkpoint 之間的切換可用性。
效能方面,基於 DeleteRange 將 RocksDB Rescale 效能提升 2-10 倍,基於 Overdraft Buffer 提升了 Checkpoint 效能。
■ 後面在 Flink Forward Asia 2022 核心技術專場分享的文章中,會有更加完整的展示!
Q&A
Q:RocksDB 與 Changelog 兩種儲存,相當於在 HDFS 上存了兩份,檔案系統容量 1.2 是如何計算得出的?
A:按 Full Checkpoint Size 計算得出。
Q:在 HDFS上的容量應該相當於兩倍?
A:不一定是兩倍。做完一次 Materialization 後,Changelog 部分的增量是會變化的。HDFS 上也會做定時清理,避免膨脹。
Q:HDFS 有兩份,在恢復時也下載了兩份資料,需要做資料版本合併嗎?
A:是的。RocksDB 先恢復,然後將 Changelog Apply ,類似於合併操作。
Q:Changelog 資料應該已經比較準確,再做合併操作是否冗餘?
A:Changelog 機制是基於 State Table 上做增量,因此作業恢復時還是需要全量資料。
更多內容
活動推薦
阿里雲基於 Apache Flink 構建的企業級產品-實時計算Flink版現開啟活動:
99 元試用 實時計算Flink版(包年包月、10CU)即有機會獲得 Flink 獨家定製衛衣;另包 3 個月及以上還有 85 折優惠!
瞭解活動詳情:https://www.aliyun.com/produc...