本文主要内容是Flink在Sink端的3种容错方式:
(1)幂等写入方式
(2)两阶段事务写入
(3)预写日志提交
幂等写入方式
Sink端主要问题:当任务失败,数据重放可能造成最终目标存储中被写入了重复数据。如果目标存储系统支持幂等写入,且数据中有合适的key主键,则flink的sink端可以完全实现端到端的最终精确一致性,在过程中有可能是不一致的。
在处理的过程中间状态的数据,可能存在不一致,但是最终是一致的。
kafka的幂等性回顾
kafka是支持事务的,pulsar也支持事务
kafka不支持幂等性,说的是Flink写入kafka的幂等性
当任务失败,重启后producer会再发送一次,序列号一定不同,所以kafka中会写入2次数据
kafka的幂等是一个会话里面幂等,会话间无法保证幂等性。
producer中的每条记录都有一个序列号,当broker收到数据后发现有相同的序列号,所以就不会再次写入
在将数据写出去之前,开启事务。
Flink两阶段事务写入
Flink中的两阶段事务提交sink,主要是利用checkpoint的两阶段提交协议和目标存储系统的事务支持机制(如:mysql、kafka、pulsar等)
Flink两阶段提交过程
(1)Sink算子在处理一批数据过程中,先通过预提交事务对外输出数据
(2)等待这批数据处理完成(收到checkpoint信号)后,向checkpoint coordinator(JobManager)上报自己checkpoint完成信息
(3)checkpoint coordinator (Job Manager)收到所有算子任务checkpoint的完成信息后,会告诉所有算子,这次checkpoint已经完成
(4)两阶段事务提交算子收到checkpoint coordinator的回调信息时,执行事务commit操作
总结:第一阶段(预提交阶段):开启事务,正常输出数据,barrier到达,预提交事务(存储本次对外事务号,以及事务状态:pending),local进行checkpoint快照,向Job Manager上报,等待notify到达
第二阶段(事务提交阶段):notify到达,提交事务,(向外部系统commit,如果成功就修改事务状态为finished)
预写日志提交-核心流程
(1)将结果数据当成状态保存,在收到checkpoint完成的通知notify时,一次性写入sink系统
(2)简单容易实现,由于数据提前在状态端进行了缓存,所以无论sink是什么系统,都能用这种方式实现
(3)DataStream API提供了一个模板类:GenericWriteAheadSink,来实现这种事务sink
抽象类GenericWriteAheadSink实现了缓存数据,在收到上游消息时,会将消息存储到state
(4)收到全局一致快照完成的notify后,调用sendValues(Iterable<IN> values, long checkpointId,long timestamp)方法向下游系统发送global commit消息
总结本文主要内容是Flink在Sink端的3种容错方式:
(1)幂等写入方式-需要满足特殊条件
(2)两阶段事务写入-需要支持事物
(3)预写日志提交-没有条件要求,都可以实现
奇迹的出现往往就在再坚持一下的时候!
感谢阅读。期待点赞、分享、关注。