这是我参与「第四届青训营 -大数据场」笔记创作活动的第6篇笔记
本文已参与「新人创作礼」活动, 一起开启掘金创作之路。
Flink端到端的Exactly-once语义
- checkpoint能保证每条数据都对各个有状态的算子更新一次,sink输出算子仍然可能下发重复的数据
- 严格意义的端到端的Exactly-once语义需要特殊的sink算子实现
两阶段提交协议
在多个节点参与执行的分布式系统中,为了协调每个节点都能同时执行或者回滚某个事务性的操作,引入了一个中心节点来统一处理所有节点的执行逻辑,这个中心节点叫做协作者(coordinator),被中心节点调度的其他业务节点叫做参与者(participant)
预提交阶段
- 协作者向所有参与者发送一个commit消息
- 每个参与的协作者收到消息后,执行事务,但是不真正提交
- 若事务成功执行完成,发送一个成功的消息(vote yes);执行失败,则发送一个失败的消息(vote no)
提交阶段
若协作者成功接收到所有参与者vote yes的消息
- 协作者向所有参与者发送一个commit消息
- 每个收到commit消息的参与者释放执行事务所需的资源,并结束这次事务的执行
- 完成步骤2后,参与者发送一个ack消息给协作者
- 协作者收到所有参与者的ack消息后,标识该事务执行完成
若协作者有收到参与者vote no的消息(或者发生等待超时)
- 协作者向所有参与者发送一个rollback消息
- 每个收到rollback消息的参与者回滚事务的执行操作,并释放事务所占资源
- 完成步骤2后,参与者发送一个ack消息给协作者
- 协作者收到所有参与者的ack消息后,标识该事务成功完成回滚
Flink中2PC Sink
预提交阶段
JM向Source发送一个checkpoint barrier,标志事务已经就开始
Source把checkpoint barrier传递给下游的所有算子
一旦开启了checkpoint功能,JobManager就在数据流中源源不断地打入屏障(barrier),作为检查点的界限。屏障随着算子链向下游传递,每到达一个算子都会触发将状态快照写入状态后端的动作。当屏障到达Kafka sink后,通过KafkaProducer.flush()方法刷写消息数据,但还未真正提交。接下来还是需要通过检查点来触发提交阶段。
提交阶段
可见,只有在所有检查点都成功完成这个前提下,写入才会成功。这符合前文所述2PC的流程,其中JobManager为协调者,各个算子为参与者(不过只有sink一个参与者会执行提交)。一旦有检查点失败,notifyCheckpointComplete()方法就不会执行。如果重试也不成功的话,最终会调用abort()方法回滚事务。