FLink-15-Flink的容错机制&checkpoint机制
Flink的容错机制
1.容错机制
Flink 是一个 stateful(带状态)的数据处理系统;
系统在处理数据的过程中,各算子所记录的状态会 随着数据的处理而不断变化;
一旦系统崩溃,需要重启后能够恢复出崩溃前的状态才能进行数据的接续处理;
因此,必须要一种机 制能对系统内的各种状态进行持久化容错;
2.Flink要实现端到端的 EOS 保证
-
核心点在于: 一条(或者一批)数据,从 注入系统、中间处理、到输出结果的整个流程中,要么每个环节都处理成功,要么失败回滚(回到从未处理过的状态)!
-
flink还未实现真正意义上的端到端的一致,只是尽可能减少异常情况的发生,来保证端到端数据的一致性。
-
flink实现了state的精确一次;什么是state的精确一次:确保故障重启后,算子所恢复的状态值,大家都统一(都是经历了相同输入数据的影响后的值);也可以这样说:一条数据只会影响状态数据一次(最终效果),如果中间发生了问题,那么发生问题的数据进入不到状态数据中,所以只有有效数据才会影响状态数据。
-
实现严 格意义上的端到端 EOS,需要下面三端的保证
- 1.source 端的保证
Flink 的很多 source 算子都能为 EOS 提供保障,如 kafka Source :- 能够记录偏移量
- 能够重放数据
- 将偏移量记录在 state 中,与下游的其他算子的 state 一起,经由 checkpoint 机制实现了“状态数 据的”快照统一
- 2.Flink内部算子状态的 EOS 语义保证
基于分布式快照算法:(Chandy-Lamport),flink 实现了整个数据流中各算子的状态数据快照统一; 既:一次 checkpoint 后所持久化的各算子的状态数据,确保是经过了相同数据的影响; 这样一来,就能确保:- 一条(或一批)数据要么是经过了完整正确处理;
- 如果这条(批)数据在中间任何过程失败,则重启恢复后,所有算子的 state 数据都能回到这条 数据从未处理过时的状态
- 3.sink 端的保证
从前文所述的 source 端和内部 state 的容错机制来看,一批数据如果在 sink 端写出过程中失败(可能 已经有一部分数据进入目标存储系统),则重启后重放这批数据时有可能造成目标存储系统中出现数 据重复,从而破坏 EOS; 对此,flink 中也设计了相应机制来确保 EOS- 采用幂等写入方式
- 采用两阶段提交(2PC,two phase)事务写入方式
- 采用预写日志 2PC 提交方式
- 1.source 端的保证
Flink的Checkpoint机制
-
checkpoint 是 flink 内部对状态数据的快照机制;
- flink 的 checkpoint 机制是源于 Chandy-Lamport 算法(分布式快照算法);
- 底层逻辑:通过插入序号单调递增的 barrier(barrier跟waterMark类似,也是一个StreamRecord),把无界数据流划分成逻辑上的数据批(段),并通过段 落标记(barrier)来为这段数据的处理,加持"事务(transaction)" 特性:
- 每一段数据流要么被完整成功处理;
- 要么回滚一切不完整的影响(状态变化);
-
checkpoint要解决的核心问题:系统崩溃时,各算子如何恢复状态,以实现数据的一致性语义。
-
checkpoint的核心是:生成快照状态的时候,各算子间需要保持状态的统一,也就是说各算子之间需要被同一批数据影响,如果这同一批数据在不同算子之间有的被影响有的不被影响,那么最终的算子状态就不统一了。
-
每个算子的状态,如果不一致(不是经过相同数据的影响),将来恢复的时候,就会产生大量的问题:
- 计算结果可能有错
- 数据有可能丢失
-
数据流经的时候,有固定的checkpoint 机制,在程序重启的时候,有checkpoint协调器加载最近完整的checkpoint快照即可实现数据的精确处理。
-
flink的checkpoint机制,不能保证数据的端到端的一致性,只能保证:
- 1.故障重启后,各算子能恢复到 一个统一的状态(经过了相同数据影响之后的状态)
- 2.数据不会被漏处理(不会发生数据丢失)
checkpoint的整体流程
- 1.Job Manager定期指派各个source算子插入barrier
- 2.每个算子做完checkpoint-n,就会向jobmanager应答
- 3.jobmanager收到所有算子对checkpoint-n应答后,才认为此次checkpoint是成功的(完整完成global)的
- 4.然后,jobmanager确认ck-n全局完成后,会向各个算子通报一次ck-n完成。
说明:checkpoint 机制的调用流程实质是 2PC。JobManager 是协调者,所有 operator task 是执行者。 start checkpoint 是 pre-commit 的开始信号,而每个 operator task 的 checkpoint 是 pre-commit 过 程,ack 是执行者 operator task 反馈给协调者 JobMaster ,最后 callback 是 commit。
对齐与非对齐checkpoint
对齐checkpoint
能保证状态的精确语义,但是他可能带来 数据处理效率(及时性)的负面影响。
- 算子收到数字流 Barrier,字母流对应 barrier 尚未到达 ;
- 算子收到数字流 Barrier,会继续从数字流中接收数据,但这些流只能被搁置,记录不能被处理, 而是放入缓存中,等待字母流 Barrier 到达。在字母流到达前, 1,2,3 数据已经被缓存。
- 字母流到达,算子开始对齐 State 进行异步快照,并将 Barrier 向下游广播,并不等待快照完毕。
- 算子做异步快照,首先处理缓存中积压数据,然后再从输入通道中获取数据。
非对齐checkpoint
非对齐的checkpoint只能保证at_least_once,不能保证精准一次。
checkpoint相关API总结
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment(conf);
/* *
* checkpoint相关配置
*/
env.enableCheckpointing(2000, CheckpointingMode.EXACTLY_ONCE); // 传入两个最基本ck参数:间隔时长,ck模式
CheckpointConfig checkpointConfig = env.getCheckpointConfig();
checkpointConfig.setCheckpointStorage("hdfs://hadoop102:8020/ckpt");
checkpointConfig.setAlignedCheckpointTimeout(Duration.ofMinutes(10000)); // 设置ck对齐的超时时长
checkpointConfig.setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE); // 设置ck算法模式
checkpointConfig.setCheckpointInterval(2000); // ck的间隔时长
//checkpointConfig.setCheckpointIdOfIgnoredInFlightData(5); // 用于非对齐算法模式下,在job恢复时让各个算子自动抛弃掉ck-5中飞行数据
checkpointConfig.setExternalizedCheckpointCleanup(CheckpointConfig.ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION); // job cancel调时,保留最后一次ck数据
checkpointConfig.setForceUnalignedCheckpoints(false); // 是否强制使用 非对齐的checkpoint模式
checkpointConfig.setMaxConcurrentCheckpoints(5); // 允许在系统中同时存在的飞行中(未完成的)的ck数
checkpointConfig.setMinPauseBetweenCheckpoints(2000); // 设置两次ck之间的最小时间间隔,用于防止checkpoint过多地占用算子的处理时间
checkpointConfig.setCheckpointTimeout(3000); // 一个算子在一次checkpoint执行过程中的总耗费时长超时上限
checkpointConfig.setTolerableCheckpointFailureNumber(10); // 允许的checkpoint失败最大次数
Flink的sink端容错机制
1.幂等写入方式(主要应用在kv格式的sink上)
-
Sink 端主要的问题是,作业失败重启时,数据重放可能造成最终目标存储中被写入了重复数据; 如果目标存储系统支持幂等写入,且数据中有合适的 key(主键),则 flink 的 sink 端完全可以利用 目标系统的幂等写入特点,来实现数据的最终一致(精确一次);
-
只是,幂等写入的方式,能实现最终一致,但依然存在弊端:
- “过程中的不一致” (如果同一批数据,在两次运行中,计算逻辑所产生的结果如果是不确定的,那么就会出现过程中的不一致。)
- 可能导致下游数据消费者出现脏读;
注: 动态过程不一致,主要出现在“输出结果非确定”的计算场景中,如,
输入: guid, event_id, event_cout
输出: guid, event_id, event_cout, insert_time(数据插入的时间或者随机数)
则重复写入 guid,event_id 相同的两次数据时,第一次的值和后面覆盖的值,是发生了变化的
-
kafka本身是支持幂等机制,但是此刻flink数据写出到kafka的时候,不支持幂等写入,因为sink端kafka没有kv格式,数据写入kafka后就代表写入了,不会出现回滚的情况。
- kafka本身的幂等机制是 kafka生产者向broker发送数据的时候,会使用ack幂等机制 写入数据到broker中,中间如果出现数据写入失败的情况,幂等机制就起作用,会重新写入数据到broker,直到写入成功为止。
-
mysql为例:
- sink如果使用幂等写入方式来保证eos
- sink如果使用事务写入方式来保证eos
- 这两者的区别:下游能更及时的拿到结果数据的话,使用幂等写入。