kafka两阶段提交、幂等以及flink结合

1 在checkpoint之间是一直pre_commit, 数据写入kafka broker, 同时在transaction协调器以及 消费者处理器之间写入本次事务的元信息;等到本次从source到sink之间的checkpoint全部完成,job manager完成checkpoint时,sink的producer才正式发出事务commit,这时候kafka之前写入broker的log才会对消费者显示有效可以读取。

以下信息取自:https://zhuanlan.zhihu.com/p/111304281

具体代码层面:

flink kafkasink的TwoPhaseCommitSinkFunction仍然留了以下四个抽象方法待子类来实现:

beginTransaction():开始一个事务,返回事务信息的句柄。

preCommit():预提交(即提交请求)阶段的逻辑。

commit():正式提交阶段的逻辑。

abort():取消事务

这四个方法实际上是flink对于sink端支持两阶段事务提交中间件的抽象,具体针对kafka sink来说,应用了kafka对应的两阶段提交的方法。

1.1 预提交阶段

FlinkKafkaProducer011.preCommit()方法的实现很简单。其中的flush()方法实际上是代理了KafkaProducer.flush()方法。

那么preCommit()方法是在哪里使用的呢?答案是TwoPhaseCommitSinkFunction.snapshotState()方法。从前面的类图可以得知,TwoPhaseCommitSinkFunction也继承了CheckpointedFunction接口,所以2PC是与检查点机制一同发挥作用的。

每当需要做checkpoint时,JobManager就在数据流中打入一个屏障(barrier),作为检查点的界限。屏障随着算子链向下游传递,每到达一个算子都会触发将状态快照写入状态后端(state BackEnd)的动作。当屏障到达Kafka sink后,触发preCommit(实际上是KafkaProducer.flush())方法刷写消息数据,但还未真正提交。接下来还是需要通过检查点来触发提交阶段。

1.2 提交阶段

FlinkKafkaProducer011.commit()方法实际上是代理了KafkaProducer.commitTransaction()方法,正式向Kafka提交事务。

该方法的调用点位于TwoPhaseCommitSinkFunction.notifyCheckpointComplete()方法中。顾名思义,当所有检查点都成功完成之后,会回调这个方法。

该方法每次从正在等待提交的事务句柄中取出一个,校验它的检查点ID,并调用commit()方法提交之。

1.3 回退阶段

可见,只有在所有检查点都成功完成这个前提下,写入才会成功。这符合前文所述2PC的流程,其中JobManager为协调者,各个算子为参与者(不过只有sink一个参与者会执行提交)。一旦有检查点失败,notifyCheckpointComplete()方法就不会执行。如果重试也不成功的话,最终会调用abort()方法回滚事务。

 

2 kafka的幂等性可以防止重复提交。每个producer可以用户显式的指定transactionId, 这样producer Id以及topic、partition和生产者发送的每条消息的递增的seq Id.这些可以唯一确定一条消息,相当于唯一键,防止broker内部数据重复写入。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章