在Flink 原理與實現:Checkpoint 這篇文章中介紹了 Flink Checkpoint 的原理以及作用,Flink 原理與實現:Savepoint
這篇文章講述了 Flink Checkpoint 和 Savepoint 的異同。有了這些基礎,你就可以在流式計算中對 Flink Checkpoint 進行配置了,下文會詳細介紹各種配置方式,以及配置原則。
1. Checkpoint 的配置
在 Flink 應用程序中配置 Checkpoint,首先需要開啓 Checkpoint,同時指定 Checkpoint 的時間間隔。
val env = StreamExecutionEnvironment.getExecutionEnvironment
// enable Checkpoint and set 10min Checkpoint Interval
env.enableCheckpointing(10 * 1000)
爲了對 Checkpoint 進行更多的配置,你需要拿到 CheckpointConfig:
val chkpConf = env.getCheckpointConfig
Flink 默認提供 Extractly-Once 保證 State 的一致性。這可以通過 CheckpointConfig 進行設置,Flink 提供了 Extractly-Once,At-Least-Once 兩種模式。
chkpConf.setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE)
如果只是設置 State 的一致性保障機制,那麼可以簡單配置成:
env.enableCheckpointing(10 * 1000, CheckpointingMode.EXACTLY_ONCE)
由於每個 Flink 應用程序的 State 大小不同,StateBackend 也可能有所不同,所以,Checkpoint 需要根據實際情況配置。Flink 默認同一時間只允許執行一個 Checkpoint,以避免佔用太多正常數據處理資源。如果在配置的 Checkpoint 時間間隔之內,一個 Checkpoint 正在生產,另一個 Checkpoint 也需要開始生產,那麼,第二個 Checkpoint 將會等到第一個 Checkpoint 生產完成纔會開始。
那麼,如果很多 Checkpoint 生產時間過長,比 Checkpoint 時間間隔還要長,會有什麼影響呢?在這種情況下,Checkpoint 的配置是不理想的,原因有二:
- 這種現象意味着應用程序的正常數據處理過程和 Checkpoint 的生產是併發的,資源是被二者共享的。所以,它將會拖慢正常數據的處理速度,無法全力消費數據,甚至導致數據的處理速度慢於數據的輸入速度。
- 因爲需要等待前一個 Checkpoint 生產完成,會使下一個 Checkpoint 延遲生產,從而導致在失敗恢復時需要更長的追趕時間。
爲了保證應用程序可以全力處理數據,你可以配置 Checkpoint 彼此之間的停頓時間。比如,你配置最小停頓時間是一分鐘,那麼在一個 Checkpoint 生產完成之後的頭一分鐘,不會有新的 Checkpoint 被拉起,這僅限於同時最多隻有一個 Checkpoint 生產的情況。
chkpConf.setMinPauseBetweenCheckpoints(60 * 1000)
如果某個應用程序的 Checkpoint 生產需要比較長的時間,但由於不用消耗很多資源,那麼這時候是可以配置 Checkpoint 更高的併發量的:
chkpConf.setMaxConcurrentCheckpoints(3)
值得注意的一點是:Savepoint 是可以和 Checkpoint 併發生產的。即使有多個 Checkpoint 正在生產的過程中,Savepoint 也會併發生產。
爲了避免有 Checkpoint 生產時間過長,導致資源一直被佔用,你可以給 Checkpoint 設置一個超時時間,Flink 默認的 Checkpoint 超時時間是 10 分鐘。
chkpConf.setCheckpointTimeout(5 * 1000)
衆所周知,Checkpoint 失敗之後,會觸發 Flink 的失敗恢復機制進行重啓。如果你想禁用這個功能,讓應用程序在 Checkpoint 失敗後繼續執行,可以用下面的方式配置(這個配置的 API 在 Flink 1.9 已經被標記成廢棄了)。
chkpConf.setFailOnCheckpointingErrors(false)
另外,在 Flink 1.9 引入了 Checkpoint 失敗次數容忍度的配置,默認是 0 次,即對 Checkpoint 的失敗是零容忍的,你可以通過 API 進行配置。
chkpConf.setTolerableCheckpointFailureNumber(3)
Checkpoint 的清除
Checkpoint 的初衷是進行失敗恢復,因此,當一個 Flink 應用程序停止時(比如,失敗終止、人爲取消等),它的 Checkpoint 就會被清除。但是,你可以通過開啓外化 Checkpoint 功能,在應用程序停止後,保存 Checkpoint。
chkpConf.enableExternalizedCheckpoints(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION)
Flink 支持兩種外化 Checkpoint:
- DELETE_ON_CANCELLATION:當應用程序完全失敗或者明確地取消時,保存 Checkpoint。
- RETAIN_ON_CANCELLATION:當應用程序完全失敗時,保存 Checkpoint。如果應用程序是明確地取消時,Checkpoint 被刪除。
切記:外化 Checkpoint 並不能代替 Savepoint。它們使用特定於 State Backend 的存儲格式,但是沒有伸縮性。因此,它們只能滿足應用程序失敗後的重啓,缺乏 Savepoint 的靈活性。
2. Checkpoint 的配置原則
上一節介紹了 Checkpoint 的配置方法,以及 Checkpoint 時間間隔與 Checkpoint 生產時間的關係對 Flink 應用程序的影響。Checkpoint 的配置需要隨着 Flink 應用程序的不同而不同。這裏簡單介紹一下 Checkpoint 的配置原則:
- Checkpoint 時間間隔不易過大。一般來說,Checkpoint 時間間隔越長,需要生產的 State 就越大。如此一來,當失敗恢復時,需要更長的追趕時間。
- Checkpoint 時間間隔不易過小。如果 Checkpoint 時間間隔太小,那麼 Flink 應用程序就會頻繁 Checkpoint,導致部分資源被佔有,無法專注地進行數據處理。
- Checkpoint 時間間隔大於 Checkpoint 的生產時間。當 Checkpoint 時間間隔比 Checkpoint 生產時間長時,在上次 Checkpoint 完成時,不會立刻進行下一次 Checkpoint,而是會等待一段時間,之後再進行新的 Checkpoint。否則,每次 Checkpoint 完成時,就會立即開始下一次 Checkpoint,系統會有很多資源被 Checkpoint 佔用,而真正任務計算的資源就會變少。
- 開啓本地恢復。如果 Flink State 很大,在進行恢復時,需要從遠程存儲上讀取 State 進行恢復,如果 State 文件過大,此時可能導致任務恢復很慢,大量的時間浪費在網絡傳輸方面。此時可以設置 Flink 應用程序本地 State 恢復,應用程序 State 本地恢復默認沒有開啓,可以設置參數
state.backend.local-recovery
值爲 true 進行激活。 - 設置 Checkpoint 保存數。Checkpoint 保存數默認是 1,也就是隻保存最新的 Checkpoint 的 State 文件,當進行 State 恢復時,如果最新的 Checkpoint 文件不可用時 (比如文件損壞或者其他原因),那麼 State 恢復就會失敗,如果設置 Checkpoint 保存數 3,即使最新的 Checkpoint 恢復失敗,那麼 Flink 也會回滾到上一次 Checkpoint 的狀態文件進行恢復。考慮到這種情況,可以通過
state.checkpoints.num-retained
設置 Checkpoint 保存數。
3. 總結
Checkpoint 是 Flink 的失敗恢復機制,它的配置對於 Flink 應用程序的性能和穩定性有着至關重要的影響。Checkpoint 需要根據 Flink 應用程序的不同而進行不同的配置,根據相關配置原則,以求達到理想的配置,使 Flink 應用程序性能和穩定性最優化。
掃碼關注公衆號:冰山烈焰的黑板報