flink 保证一致性的 barrier对⻬齐

 barrier对⻬齐
1.什么是barrier对⻬齐?
⼀旦Operator从输⼊入流接收到CheckPoint barrier n,它就不能处理理来⾃该流的任何数据记录,直到它从其他所有输入接收到barrier n为止。否则,它会混合属于快照n的记录和属于快照n + 1的记录接收到barrier n的流暂时被搁置。从这些流接收的录不会被处理,⽽是放⼊输⼊缓冲区。
⼀旦最后所有输入流都接收到barrier n,Operator就会把缓冲区中pending 的输出数据发出去,然后把CheckPoint barrier n接着往下游发送这里还会对⾃身进行快照之后,Operator将继续处理理来⾃所有输⼊流的记录,在处理来⾃流的记录之前先处理来⾃输⼊缓冲区的记录
2.什么是barrier不对齐?
barrier不对齐就是指当还有其他流的barrier还没到达时,为了不影响性能,也不⽤理会,直接处理barrier之后的数据。等到所有流的barrier的都到达后,就可以对该Operator做CheckPoint了了
为什么要进行barrier对齐?不对齐到底⾏不行?
答:Exactly Once时必须barrier对⻬齐,如果barrier不对⻬齐就变成了At Least Once
后⾯的部分主要证明这句话CheckPoint的⽬的就是为了保存快照,如果不对齐,那么在chk-100快照之前,已经处理了⼀些chk-100 对应的offset之后的数据,当程序从chk-100恢复任务时,chk-100对应的offset之后的数据还会被处理一次所以就出现了重复消费。如果听不懂没关系,后⾯有案例让您懂结合pv案例来看,之前的案例为了简单,描述的kafka的topic只有1个partition,这⾥里为了讲述barrier对齐,所以topic有2个partittion

结合业务,先介绍⼀下上述所有算⼦子在业务中的功能Source的kafka的Consumer,从kakfa中读取数据到flink应用中TaskA中的map将读取到的⼀条kafka⽇志转换为我们需要统计的app_idkeyBy 按照app_id进⾏行行keyBy,相同的app_id 会分到下TaskB的同⼀个实例例中TaskB的map在状态中查出该app_id 对应的pv值,然后+1,存储到状态中利用Sink将统计的pv值写⼊入到外部存储介质中我们从kafka的两个partition消费数据,TaskA和TaskB都有两个并行度,所以总共flink有4个Operator实例例,⾥我们称之为 TaskA0、TaskA1、TaskB0、TaskB1假设已经成功做了99次CheckPoint,这⾥里里详细解释第100次CheckPoint过程JobManager内部有个定时调度,假如现在10点00分00秒到了了第100次CheckPoint的时间了了,JobManager的CheckPointCoordinator进程会向所有的Source Task发送CheckPointTrigger,也就是向TaskA0、TaskA1发送CheckPointTriggerTaskA0、TaskA1接收到CheckPointTrigger,会往数据流中安插barrier,将barrier发送到下游,在⾃⼰的状态中记录barrier安插的offset位置,然后自身做快照,将offset信息保存到状态后端这里假如TaskA0消费的partition0的offset为10000,TaskA1消费的partition1的offset为10005。那么状态中会保存 (0,10000)(1,10005),表示0号partition消费到了了offset为10000的位置,1号partition消费到了offset为10005的位置然后TaskA的map和keyBy算⼦子中并没有状态,所以不不需要进⾏快照。接着数据和barrier都向下游TaskB发送,相同的app_id 会发送到相同的TaskB实例例上,这⾥里里假设有两个app:app0和app1,经过keyBy后,假设app0分到了TaskB0上,app1分到了了TaskB1上。基于上⾯面描述,TaskA0和TaskA1中的所有app0的数据都发送到TaskB0上,所有app1的数据都发送到TaskB1上。现在我们假设TaskB0做CheckPoint的时候barrier对⻬齐了了,TaskB1做CheckPoint的时barrier不对齐,当然不能这么配置,我就是举这么个例子,带大家分析⼀下
barrier不对齐到底对统计结果有什么影响?
上⾯说了chk-100的这次CheckPoint,offset位置为(0,10000)(1,10005),TaskB0使⽤用barrier对⻬齐,也就是说TaskB0不会处理barrier之后的数据,所以TaskB0在chk-100快照的时候,状态后端保存的app0的pv数据是从程序开始启动到kafka offset位置为(0,10000)(1,10005)的所有数据计算出来的pv值,⼀条不多(没处理barrier之后,所以不会重复),⼀条不少(barrier之前的所有数据都处理了,所以不会丢失),假如保存的状态信息为(app0,8000)表示消费到(0,10000)(1,10005)offset的时候,app0的pv值为8000TaskB1使⽤用的barrier不对齐,假如TaskA0由于服务器的CPU或者网络等其他波动,导致TaskA0处理数据较慢,而TaskA1很稳定,所以处理理数据⽐比较快。导致的结果就是TaskB1先接收到了TaskA1的barrier,由于配置的barrier不对齐,所以TaskB1会接着处理TaskA1 barrier之后的数据,过了了2秒后,TaskB1接收到了TaskA0的barrier,于是对状态中存储的app1的pv值开始做CheckPoint 快照,保存的状态信息为(app1,12050),但是我们知道这个(app1,12050)实际上多处理理了了2秒TaskA1发来的barrier之后的数据,也就是kafka topic对应的partition1offset 10005之后的数据,app1真实的pv数据肯定要⼩小于这个12050,partition1的offset保存的offset虽然是10005,但是我们实际上可能已经处理到了offset10200的数据,假设就是处理到了10200虽然状态保存的pv值偏⾼了,但是不能说明重复处理,因为我的TaskA1并没有再次去消费partition1的offset 10005~10200的数据,所以相当于也没有重复消费,只是展示的结果更实时了分析到这⾥里,我们先梳理⼀下我们的状态保存了什么:
chk-100
offset:(0,10000)(1,10005)
pv:(app0,8000) (app1,12050)
接着程序在继续运行,过了10秒,由于某个服务器器挂了,导致我们的四个Operator实例有⼀个Operator挂了,所以Flink会从最近⼀次的状态恢复,也就是我们刚刚详细讲的chk-100处恢复,那具体是怎么恢复的呢?Flink 同样会起四个Operator实例,我还称他们是 TaskA0、TaskA1、TaskB0、TaskB1。四个Operator会从状态后端读取保存的状态信息。从offset:(0,10000)(1,10005) 开始消费,并且基于 pv:(app0,8000)(app1,12050)值进⾏行行累加统计然后你就应该会发现这个app1的pv值12050实际上已经包含了partition1的offset 10005~10200的数据,所以partition1从offset 10005恢复任务时,partition1的offset 10005~10200的数据被消费了了两次TaskB1设置的barrier不对齐,所以CheckPoint chk-100对应的状态中多消费了了barrier之后的一些数据(TaskA1发送),重启后是从chk-100保存的offset恢复,这就是所说的At Least Once由于上⾯面说TaskB0设置的barrier对⻬齐,所以app0不不会出现重复消费,因为app0没有消费offset:(0,10000)(1,10005) 之后的数据,也就是所谓的Exactly Once
看到这⾥里你应该已经知道了哪种情况会出现重复消费了,也应该要掌握为什么barrier对⻬就是Exactly Once,为什么barrier不对齐就是 At Least Once

猜你喜欢

转载自blog.csdn.net/Baron_ND/article/details/108064175