一、背景
Flink的容错机制,就是checkpoint;把状态保存起来,用于容错;否则,状态就失去了存在的意义。
二、checkpoint详解
1)概念
①一种连续周期性绘制数据流状态的机制。这种机制确保即使程序出现故障,也可以顺利恢复到故障之前的状态,确保exactly once语义的保证。
注意:这种保证,只能在flink内部系统做保证,对于外部的source和sink,需要外部主键一同保证
②全局快照,持久化保存所有的task和operator的state
③可以通过配置,使用at least once语义保证
④checkpoint是通过分布式snapshot实现的
2)特点
①可异步:在程序正常运行的过程中,异步完成,不会干扰程序的正常运行
②全量/增量:一般是全量;也可设置增量
③barrier机制
④失败后回滚最近一次成功的checkpoint
3)前提条件
①在一定时间内可回溯的DataSource(故障是可以恢复),常见的有:
- 可持久化的队列:Kafka,RabbitMQ等
- 文件系统:HDFS,S3,GFS,NFS,Ceph
②可持久化存储state的存储系统,通常使用分布式文件系统
- 一般使用HDFS,S3,GFS,NFS,Ceph等
三、过程
1)checkpoint
将各个state保存起来到指定的存储系统中(checkpoint)
2)restore
恢复所有状态
四、使用
1)第一步:启用checkpoint
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// checkpoint默认是禁用的;启用checkpoint
// 每1000毫秒做一次checkpoint
env.enableCheckpointing(1000);
// 设置checkpoint的模式为 exactly-once(默认配置)
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
// 设置每两个checkpoint之间最小时间间隔
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
// 设置checkpoint超时时间
env.getCheckpointConfig().setCheckpointTimeout(60000);
// 设置同一时间checkpoint的最大并行数
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
// 任务流取消和故障时会保留Checkpoint数据,以便根据实际需要恢复到指定的Checkpoint
env.getCheckpointConfig().enableExternalizedCheckpoints(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
①checkpoint的模式 CheckpointMode
- CheckpointMode.EXACTLY_ONCE
- CheckpointMode.AT_LEAST_ONCE
- 一般选择EXACTLY_ONCE,除非场景要求极低的延迟(几毫秒)
- 如果需要保证整个流程的EXACTLY_ONCE,source和sink也需要保证EXACTLY_ONCE
②checkpoint的保留策略 ExternalizedCheckpointCleanup
- 默认情况下,检测点不被保留,仅用于从故障中恢复作业,可以启用外部持久化检查点,同时制定保留策略
- ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION,在作业被取消时保留检查点;这种情况下,必须在作业取消之后,手动清理检查点状态。
- ExternalizedCheckpointCleanup.DELETE_ON_CANCELLATION,在作业被取消时清理检查点;这种情况下,检查点状态只有在作业失败重启时可用,手动取消作业,检查点被清理不可用。
③checkpoint的超时时间
- env.getCheckpointConfig().setCheckpointTimeout(6000)
- 超过时间没有完成,则会被终止
④checkpoint的最小间隔
- env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500)
- 用于指定上一个checkpoint完成之后至少等多久才可以发出另一个checkpoint
- 当指定这个参数时,maxConcurrentCheckpoints的值为1
备注:个人觉得,设置周期并设置最小间隔 最合理
⑤checkpoint的最多并行度
- env.getCheckpointConfig().setMaxConcurrentCheckpoints(1)
- 用于指定同时运行的checkpoint可以有多少个
⑥checkpoint的异常处理
- env.getCheckpointConfig().setFailOnCheckpointingErrors(true)
- 用于指定在checkpointing发生异常时,是否应该使该task失败重试
- 默认为true
- 如果设置为false,在checkpoint失败后,任务仍然会继续运行
2)第二步:选择合适的state Backend
①快照保存位置
- State Backend决定:MemoryStateBackend(默认)、FsStateBackend、RocksDBStateBackend
- 默认state保存在taskmanager的内存中,checkpoint存储在JobManager的内存中(MemoryStateBackend)
②保存的内容
Checkpoint机制会持久化所有状态的一次性快照,这些状态包括:
非用户定义的状态:timers、非用户定义的stateful operators(connectors,windows)
用户定义的状态:用户自定义的stateful operator所使用的Keyed State 和 Operator State
3)第三步:配置重启策略
①重启策略说明
Flink支持不同的重启策略,这些策略控制 在出现故障时如何重新启动job
Restart Strategy | 配置项 | 默认值 | 说明 |
固定延迟(Fixed delay) | restart-strategy: fixed-delay | | 如果超过最大尝试次数,作业最终会失败,在连续两次重启尝试之间等待固定时间 |
restart-strategy: fixed-delay.attempts: 3 | 1(启动Checkpoint和延迟策略使用fixed-delay,但是没配置fixed-delay.attempts)或者 Integer.MAX_VALUE(启用checkpoint但未指定重启策略时) | ||
restart-strategy: fixed-delay.delay: 10s | akka.ask.timeout (启动checkpoint和延迟策略使用fixed-delay,但是没配置fixed-delay.delay)或者 10s(启动checkpoint,但是没指定重启策略) | ||
失败率(Failure rate) | restart-strategy: failure-rate | | 在失败后重新启动作业,但是当超过故障率(每个时间间隔的故障)时,作业最终会失败,在连续两次重启尝试之间等待固定的时间 |
restart-strategy: failure-rate.max-failures-per-interval: 3 | 1 | ||
restart-stragery: failure-rate.failure-rate-interval: 5 min | 1 minute | ||
restart-stragery: failure-rate.delay: 10s | akka.ask.timeout | ||
无启动(No restart) | restart-strategy: none | | 如果没有启动checkpointing,则使用无重启(no restart)策略 |
注意:代码配置会覆盖配置文件配置,即代码配置优先于配置文件配置。
②tips
- 如果没有启用checkpointing,则使用无重启(no restart)策略
- 如果启用了checkpointing,但没有配置重启策略,则使用固定延迟(fixed-delay)策略,其中尝试重启次数是Integer.MAX_VALUE
- 重启策略可以在flink-conf.yaml中配置,表示全局的配置。也可以在应用代码中动态指定,会覆盖全局配置
4)三个保存策略详解
①MemoryStateBackend
- MemoryStateBackend在Java堆上维护状态,Key/value状态和窗口运算符使用哈希表存储值和计时器等
- Checkpoint时,MemoryStateBackend对State做一次快照,并在向JobManager发送checkpoint确认完成的消息中带上此快照数据,然后快照就会存储在JobManager的堆内存中
- MemoryStateBackend可以使用异步方式进行快照(默认开启),推荐使用异步的方式,避免阻塞。如果极特殊情况不希望异步,可以在构造的时候传入false(也可以通过全局配置文件指定),如下
- 限制:
单个state的大小限制为5MB,可以在MemoryStateBackend的构造函数中增加
不论如何配置,state的大小都无法大于 akka.framesize(JobManager 和 TaskManager之间发送的最大消息的大小默认是10MB)
JobManager必须有足够的内存大小 - 使用场景:
本地开发和测试
小状态job,如只使用Map、FlatMap、Filter... 或 Kafka Consumer
②FsStateBackend
- 需要配置一个文件系统的URL,比如"hdfs://namenode:40010/flink/checkpoint"或者"file:///data/flink/checkpoints"
- FsStateBackend在TaskManager的内存中持有正在处理的数据。Checkpoint时将state snapshot写入文件系统目录下的文件中。文件的路径等元数据会传递给JobManager,存在其内存中(或者在HA模式下,存储在元数据checkpoint中)
- FsStateBackend可以使用异步的方式进行快照(默认开启),推荐使用异步的方式避免阻塞。如果极特殊情况下不希望异步,可以在构造的时候传入false(也可以通过全局配置文件制定),如下
- 使用场景:
大状态,长窗口,大键/值状态的job
所有高可用性的情况
③RocksDBStateBackend
- Flink内部维护,不需要用户维护,对于用户透明
- RocksDBStateBackend需要配置一个文件系统的URL,如"hdfs://namenode:40010/flink/checkpoint"或者"file:///data/flink/checkpoints"。
- RocksDBStateBackend将运行中的数据保存在RocksDB数据库中,(默认情况下)存储在TaskManager数据目录中。在Checkpoint时,整个RocksDB数据库将被checkpointed到配置的文件系统中和目录中。文件的路径等元数据会传输给JobManager,存在其内存中(或者在HA模式下,存储在元数据checkpoint中)。
- RocksDBStateBackend总是执行异步快照
- 限制:
RocksDB JNI API是基于 byte[],因此 key 和 value 最大支持大小为2^31个字节(2GB)。RocksDB自身在支持较大value时候有问题(merge operations in RocksDB(e.g. ListState)) - 适用场景
超大状态、超长窗口、大键/值状态的job
所有高可用性的情况 - 与前两种状态后端对比
目前只有RocksDBStateBackend支持增量checkpoint(默认全量)
状态保存在数据库中,即使用RocksDB可以保存的状态量仅受可用磁盘空间量的限制,相比其他状态后端可保存更大的状态,但开销更大(读/写需要反序列化 / 序列化去检索 / 存储状态),吞吐受到限制
④StateBackend总结
State Backend | in-flight | checkpoint | 异步 | 增量checkpoint | 吞吐 | 适用场景 |
MemoryStateBackend(默认) | TM Memory | JM Memory | 默认异步 | 不支持 | 高 | 调试、无状态、小状态或对数据丢失或者重复无要求的job |
FsStateBackend | TM Memory | FS / HDFS | 默认异步 | 不支持 | 高 | 大状态、长窗口、大键 / 值状态的job |
RocksDBStateBackend | RocksDB on TM | FS / HDFS | 总是异步 | 支持 | 低 | 越大状态、超长窗口、大型KV结构 |
⑤StateBackend配置
- 全局配置(配置文件conf/flink-conf.yaml)
# The backend that will be used to store operator state checkpoints
state.backend: filesystem
# Direcroty for storing checkpoints
state.checkpoints.dir: hdfs://namenode:40010/flink/checkpoints
- 每个job单独配置State Backend(可覆盖全局配置)
- Checkpointing的相关配置(conf/flink-conf.yaml)
配置项 | 默认值 | 说明 |
(*)state.backend | (none) |
|
(*)state.backend.async | true | 用于指定backend是否使用异步,有些不支持async或者只支持async的state backend可能会忽略这个参数 |
state.backend.fs.memory-threshold | 1024 | 用于指定存储state的files大小阈值,如果小于该值,则会存储在root checkpoint metadata file |
state.backend.incremental | false | 用于指定是否采用增量checkpoint,有些不支持增量checkpoint的backend会忽略该配置;目前只有rockddb支持 |
state,backend.local-recovery | false | |
(*)state.checkpoints.dir | (none) |
|
(*)state.checkpoints.num-retained | 1 | 用于指定保留的已完成的checkpoints最大个数 |
(*)state.savepoints.dir | (none) |
|
taskmanager.state.local.root-dirs | (none) | |
⑥使用RocksDBStateBackend
- 特有配置(conf/flink-conf/yaml)
配置项 | 默认值 | 说明 |
state.backend.rocksdb.localdir | (none) | |
state.backend.rocksdb.timerservice.factory | "HEAP" | 指定timer service状态存储在哪里,HEAP / ROCKSDB |
- 代码配置
备注:以上配置,需要在pom中添加如下依赖