Checkpoint
Flink 中的 State 在上一篇中介紹過,為了使 State 容錯,需要有 State checkpoint(狀態檢查點)。Checkpoint 允許 Flink 恢復流的 State 和處理位置,從而為程序提供與無故障執行相同的語義。Checkpoint 機制在 Flink 容錯機制 中有更詳細介紹。
Checkpoint 使用的先決條件:
- 一個持久化的,能夠在一定時間范圍內重放記錄的數據源。例如,持久化消息隊列:Apache Kafka,RabbitMQ,Amazon Kinesis,Google PubSub 或文件系統:HDFS,S3,GFS,NFS,Ceph...
- State 持久化存儲系統,通常是分布式文件系統:HDFS,S3,GFS,NFS,Ceph...
啟用和配置
Checkpoint 默認情況下是不啟用的。StreamExecutionEnvironment
對象調用 enableCheckpointing(n)
啟用 Checkpoint,其中n
是以毫秒為單位的 Checkpoint 間隔。
Checkpoint 的配置項包括:
恰好一次(exactly-once)或至少一次(at-least-once):Checkpoint 支持這兩種模式。對于大多數應用來說,恰好一次是優選的。至少一次可能在某些要求超低延遲(幾毫秒)的應用程序使用。
Checkpoint 超時時間:在超時時間內 checkpoint 未完成,則中止正在進行的 checkpoint。
-
Checkpoint 最小間隔時間(毫秒):如果設置為5000,表示在上一個 checkpoint 完成后的至少5秒后才會啟動下一個 checkpoint,不論 checkpoint 的持續時間和間隔是多少。即使 checkpoint 間隔永遠不會小于此參數。是為了保證 checkpoint 之間能夠完成一定量的數據處理工作。
配置 time between checkpoint 相比配置 checkpoint interval 通常更容易。因為 checkpoint 耗時有時會明顯比平時更長,time between checkpoint 更不容易收到影響(例如,目標存儲系統臨時性的響應緩慢)
這個值還意味著并發 checkpoint 的數量是一個
-
Checkpoint 并發數:默認情況下,當一個 checkpoint 處于運行狀態時,系統不會觸發另一個 checkpoint。確保整個拓撲結構不會花費太多時間用于 checkpoint。該設置可以設置多個重疊的 checkpoint,特點的場景可能會需要。
當設置 time between checkpoint 時,不能使用此配置。
外部 checkpoint:可以配置在系統外部持久化 checkpoint。Checkpoint 信息寫入外部持久存儲,在作業失敗時不會自動清除,因此作業失敗時可以用來恢復。
Checkpoint 出錯時,任務狀態:決定了如果在 checkpoint 過程中發生錯誤,當前任務是否將失敗或繼續執行。默認會任務失敗。
val env = StreamExecutionEnvironment.getExecutionEnvironment()
// 啟用 checkpoint 間隔 1000 ms
env.enableCheckpointing(1000)
// 高級選項:
// 設置 exactly-once 模式
env.getCheckpointConfig.setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE)
// 設置 checkpoint 最小間隔 500 ms
env.getCheckpointConfig.setMinPauseBetweenCheckpoints(500)
// 設置 checkpoint 必須在1分鐘內完成,否則會被丟棄
env.getCheckpointConfig.setCheckpointTimeout(60000)
// 設置 checkpoint 失敗時,任務不會 fail,該 checkpoint 會被丟棄
env.getCheckpointConfig.setFailTasksOnCheckpointingErrors(false)
// 設置 checkpoint 的并發度為 1
env.getCheckpointConfig.setMaxConcurrentCheckpoints(1)
相關配置
更多相關參數可以通過 conf/flink-conf.yaml
全局配置
配置項 | 默認值 | 描述 |
---|---|---|
state.backend | (none) | 選擇 state backend 實現 |
state.backend.async | true | state backend 使用異步方法。有些不支持異步,或者僅支持異步的可并忽略此選項 |
state.backend.fs.memory-threshold | 1024 | 存儲 state 數據文件的最小規模,如果小于該值則會存儲在 root checkpoint metadata file |
state.backend.incremental | false | 是否采用增量 checkpoint,有些不支持增量的可并忽略此選項 |
state.backend.local-recovery | false | |
state.checkpoints.dir | (none) | 用于指定 checkpoint 數據存儲目錄,目錄必須對所有參與的 TaskManagers 和 JobManagers 可見 |
state.checkpoints.num-retained | 1 | 指定保留已完成的 checkpoint 數量 |
state.savepoints.dir | (none) | 用于指定 savepoint 數據存儲目錄 |
taskmanager.state.local.root-dirs | (none) |
選擇 State backend
Checkpoint 的存儲的位置取決于配置的 State backend(JobManager 內存,文件系統,數據庫...)。
默認情況下,State 存儲在 TaskManager 內存中,Checkpoint 存儲在 JobManager 內存中。Flink 支持在其他 state backend 中存儲 State 和 Checkpoint。可以通過如下方法配置:StreamExecutionEnvironment.setStateBackend(…)
,下面有更詳細的介紹。
迭代任務中使用
Flink 目前僅為沒有迭代的作業提供處理保證。在迭代作業上啟用 checkpoint 會導致異常。為了強制對迭代程序執行 checkpoing,需要設置一個特殊標志:env.enableCheckpointing(interval, force = true)
。
在失敗期間,處在循環邊界的記錄(以及與相關的 State 變化)將丟失。
State backend
Flink 提供了不同的 State backend,支持不通的 State 存儲方式和位置。默認會使用配置文件 flink-conf.yaml
指定的選項,也可以在每個作業中設置來覆蓋默認選項:
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
env.setStateBackend(...);
Flink 自帶了以下幾種開箱即用的 state backend:
- MemoryStateBackend
- FsStateBackend
- RocksDBStateBackend
在沒有配置的情況下,系統默認使用 MemoryStateBackend
三種 State backend 介紹
MemoryStateBackend
使用 MemoryStateBackend
,在 checkpoint 中對 State 做一次快照,并在向 JobManager 發送 checkpoint 確認完成的消息中帶上此快照數據,然后快照就會存儲在 JobManager 的內存堆中。
MemoryStateBackend
的限制:
- 單個 State 的大小默認限制為5MB,可以在
MemoryStateBackend
的構造函數中增加。 - 不論如何配置,State 大小都無法大于
akka.framesize
(JobManager 和 TaskManager 之間發送的最大消息的大小) - JobManager 必須有足夠的內存大小
MemoryStateBackend
適用以下場景:
- 本地開發和調試
- 只持有很小的狀態,如方法:Map、FlatMap、Filter... 或 Kafka Consumer
FsStateBackend
FsStateBackend
需要配置一個文件系統的URL來,如 "hdfs://namenode:40010/flink/checkpoint" 或 "file:///data/flink/checkpoints"。
FsStateBackend
在 TaskManager 的內存中持有正在處理的數據。Checkpoint 時將 state snapshot 寫入文件系統目錄下的文件中,文件的路徑會傳遞給 JobManager,存在其內存中。
FsStateBackend
默認是異步操作,以避免在寫 state snapshot 時阻塞處理程序。如果要禁用異步,可以在 FsStateBackend
構造函數中設置:
new FsStateBackend(path, false);
FsStateBackend
適用以下場景:
- State 較大,窗口時間較長和 key/value 較大的 State
- 所有高可用性的情況
RocksDBStateBackend
RocksDBStateBackend
需要配置一個文件系統的URL來,如 "hdfs://namenode:40010/flink/checkpoint" 或 "file:///data/flink/checkpoints"。
RocksDBStateBackend
在 RocksDB 中持有正在處理的數據,RocksDB 在 TaskManager 的數據目錄下。Checkpoint 時將整個 RocksDB 寫入文件系統目錄下的文件中,文件的路徑會傳遞給 JobManager,存在其內存中。
RocksDBStateBackend
通常也是異步的。
RocksDBStateBackend
的限制:
RocksDB JNI API 是基于 byte[],因此 key 和 value 最大支持大小為2^31 個字節。RocksDB 自身在支持較大 value 時候有一些問題。
RocksDBStateBackend
與 FsStateBackend
同樣適用以下場景:
- State 較大,窗口時間較長和 key/value 較大的 State
- 所有高可用性的情況
- 目前唯一支持增量 checkpoint。
與前兩者相比(處理狀態下的 State 還是保存在內存中),使用 RocksDB 可以保存的狀態量僅受可用磁盤空間量的限制。這也意味著可以實現的最大吞吐量更低,后臺的所有讀/寫都必須通過序列化和反序列化來檢索/存儲 State,這也比使用基于堆內存的方式代價更昂貴。
性能比較
Flink 支持 Standalone 和 on Yarn 的集群部署模式,以 Windowed Word Count 處理為例測試三種 State backends 在不通集群部署上的性能差異(來源:美團 Flink _Benchmark)
Standalone 時的存儲路徑為 JobManager 上的一個文件目錄,on Yarn 時存儲路徑為 HDFS 上一個文件目錄。
不同 State backend 吞吐量對比
- 使用 FileSystem 和 Memory 的吞吐差異不大(都是使用堆內存管理處理中的數據),使用 RocksDB 的吞吐差距明顯。
- Standalone 和 on Yarn 的總體差異不大,使用 FileSystem 和 Memory 時 on Yarn 模式下吞吐稍高,相反的使用 RocksDB 時 Standalone 模式下的吞吐稍高。
不同 State backend 延遲對比
- 使用 FileSystem 和 Memory 時延遲基本一致且較低。
- 使用 RocksDB 時延遲稍高,且由于吞吐較低,在達到吞吐瓶頸附近延遲陡增。其中 on Yarn 模式下吞吐更低,延遲變化更加明顯。
State backend 的選擇
StateBackend | in-flight | checkpoint | 吞吐 | 推薦使用場景 |
---|---|---|---|---|
MemoryStateBackend | TM Memory | JM Memory | 高 | 調試、無狀態或對數據丟失或重復無要求 |
FsStateBackend | TM Memory | FS/HDFS | 高 | 普通狀態、窗口、KV 結構 |
RocksDBStateBackend | RocksDB on TM | FS/HDFS | 低 | 超大狀態、超長窗口、大型 KV 結構 |
Reference:
https://flink.xskoo.com/dev/stream/state/checkpointing.html
https://tech.meituan.com/Flink_Benchmark.html