Flink 如何通过2PC实现Exactly-once语义 (源码分析)

Flink通过全局快照能保证内部处理的Exactly-once语义

但是端到端的Exactly-once还需要下游数据源配合,常见的通过幂等或者二阶段提交这两种方式保证

这里就来分析一下Sink二阶段提交的Flink源码是如何实现的

本文源码基于Flink1.14

老版本的话看TwoPhaseCommitSinkFunction,现在用SinkWriter逻辑都是差不多的

先来看下我们的主角  org.apache.flink.streaming.runtime.operators.sink.SinkOperator 类

1阶段. 在barrier到齐准备触发checkpoint之前

调用了数据源的预提交方法 prepareCommit

来看下已kafka为例具体做了什么

 kafkaWriter就是调用了生产者的flush方法,在已经开始的事务里面刷数据

2阶段. 触发checkpoint保存状态数据的时候 snapshotState 方法

 以kafka为例

 会启动下一个checkpoint的kafka事务,直接就begin事务了,接着

用这次checkpoint需要commit的kafkaCommiter更新了状态, 会被保存下来,这里有事务信息的后面会用到

3阶段. 当checkpoint完成以后

 已kafka为例,会直接提交事务了commit

 

这里可能会有疑问,,如果我只预提交了,还没有commit这时候跪了,那我从checkpoint恢复起来,那不就有问题了吗

带着疑问看下最后一个阶段

4阶段. 当任务失败从checkpoint恢复的时候

初始化的时候会恢复状态

可以看到会将上面说的上次checkpoint需要commiter的放到recoveredCommittables恢复队列里面

然后retrayWithDelay,就会根据我们保存的kafka事务信息id等去判断,上一次事务的状态,如果是预提交的话,就会先去commit了

总结一下流程:

prepareSnapshotPreBarrier快照触发前, 预提交事务,kafka里面就是flash
snapshotState快照保存时,开启一个新的事务kafka就是beginTransation,并且保存这次要提交的事务信息
notifyCheckpointComplete快照完成以后,调用对应的commit提交事务 , kafka就是commitTransation
initializeState从快照恢复,会先判断上次事务的状态如果还没提交会先提交



 

 

 

 

 

posted @ 2022-01-26 18:31  ljygz  阅读(854)  评论(0编辑  收藏  举报