Flink中的状态一致性(再细说下Checkpoint)

    之前写过一篇文章分析过CheckPoint执行时候的内部流程《Flink的ExactlyOnce语义与Checkpoint的实现》,但是当时细节没有说的太清楚,所以本文就是细说下CheckPoint的执行流程,然后结合Kafka说明下,Flink在和Kafka结合使用时如何真正实现端到端的ExactlyOnce语义。

 

CheckPoint (barrier对齐版)执行流程图示:

    CheckPoint流程在之前那篇文章里面已经说过了,这里再提一下。JobManager上的CheckPointCoordinator会定时触发CheckPoint的执行。

    CheckPointCoordinator首先会先往Source端注入barrier记录,Source会立刻将barrier广播到下游的task,以便让下游的task尽可能同时执行CheckPoint。各个Task接收到barrier消息之后会保存自己operator的状态。operator都完成state的保存之后,会向Jobmanager报告。JobManager确认所有的operator都完成state保存之后,JobManager会标记此次CheckPoint状态为Completed CheckPoint,本次CheckPoint操作才算真正完成。如果Checkpoint超时了或者失败了,会取消本次Checkpoint。整个流程图如下所示:

    注意!!!上述步骤说的是Flink1.10版本的功能。Flink1.11版本在Checkpoint中引入了一个新的机制:Unaligned Checkpoints(非对齐Checkpoint),它的目的是将Checkpoint机制与反压机制分开,避免Checkpoint在高反压场景下的速度慢以及造成的Job不稳定问题

 

Checkpoint与反压机制耦合造成Job不稳定问题分析:

    Checkpoint机制能很好的保障能够保证Flink Job从失败中重新恢复时数据的准确性和一致性问题,是Flink实现有状态计算Exactly Once语义的关键。如果Checkpoint执行成功且耗时很短,表明作业运行状态良好,没有存在异常或者反压情况。但是如果存在高反压情况,就会导致Checkpoint可能出现各种问题,这个时候一致性就无法保障了。

    Flink1.10 Exactly_Once语义下的Checkpoint机制,在某个Task接收到input channel中的barrier消息之后,会阻塞当前channel,直到所有的input channel都收到了barrier消息之后,再执行state的checkpoint操作(这个机制被称为是barrier对齐)。Checkpoint执行完毕之后,才会放开阻塞的channel,让数据继续进入operator。

    正常情况下,这套流程运行良好没有问题。但是假如一旦某个算子出现了反压,比如我们在程序中调用了外部算法,并且外部算法耗时很久,这个时候该算子就有可能出现反压情况,而反压又限制了数据的流动,有可能导致下游Task长时间接收不到barrier消息,最终有可能导致checkpoint执行时长超过单次checkpoint任务能够容忍的最大时长从而导致checkpoint整体的失败。并且barrier对齐本身也有可能成为一个反压的源头,影响上下游算子的效率。

    所以Flink 1.11引入了Unaligned Checkpoints机制,和之前的Checkpoint机制的区别在于它规避了barrier对齐这一步骤,不仅缓存State信息,同时还缓存部分待处理的数据,加快了Checkpoint的速度,解耦了Checkpoint与反压机制,有利于程序的稳定运行,同时还支持Exactly-Once语义!

 

Checkpoint源码再细说下:

Checkpoint在Source和下游Task上的触发:

    Flink1.11触发Checkpoint的流程和1.10版本的一致,Source中触发Checkpoint的入口是triggerCheckpointAsync()方法。下游Task Checkpoint触发的入口会比较复杂一点:下游Task会创建CheckpointBarrierHandler,专门来通知并处理barrier信息。并且设置不同的语义会对应创建不同的Handler,不同的Handler有不用的barrier对齐处理机制:

    EXACTLY_ONCE对应的handler有两种CheckpointBarrierUnaligner和CheckpointBarrier,前者不需要进行barrier对齐,后者需要进行barrier对齐。

    前者达到(numBarriersReceived + numClosedChannels == totalNumberOfInputChannels)条件即在所有Channel的barrier都到达之后,才会notifyCheckpoint(receivedBarrier, latestAlignmentDurationNanos)。

    后者只要有一个Input Channel的barrie到达了,就会触发threadSafeUnaligner.notifyBarrierReceived(receivedBarrier, channelInfo) –> handleNewCheckpoint(barrier) -> initCheckpoint() -> notifyCheckpoint(),其中initCheckpoint()内部会专门初始化一个ChannelStateWriter对象,它负责在checkpoint或者是savepoint过程中把各个input channel的inflight buffer和operator的输出缓存(ResultSubpartition)的内容异步记录到checkpoint。

   

Checkpoint的执行:

数据进入到Task中是通过读取channel中的数据,然后调用processInput方法:

先处理数据,再判断barrier,相当于室友一个顺序的过程,所以才能做到阻塞Channel,不让barrier之后的数据流动:

    Checkpoint是一个Event,Task收到这个消息再执行Checkpoint。Source和下游Task 执行Checkpoint时,内部都会执行performCheckpoint()方法。performCheckpoint()执行时,整体流程源码如下所示:

    step0和step1和之前一样,就是检查当前Checkpoint是否有效,取消过期的Checkpoint并做一些准备工作。Unaligned Checkpoint机制主要影响的是step2和step3,所以下面来详细说明下step2和step3,同时本文还会细说下step4,因为此前文章没有细说这一部分的内容。

 

step2 & step3:

    step2负责将barrier发送到下游Task,如果使用的是Unaligned Checkpoints,那么当前barrier所在的Buffer就会放置到发送到下游Task数据的最前面:

    step3看方法名称,负责持久化InflightData,Inflight data指的是input channel的receivedBuffer范围内,在id为当前checkpoint id的barrier之后的所有数据buffer,即checkpoint也要存储channel中的数据了!

    step2和step3就是实现非对齐barrier checkpint的关键,它允许算子优先摄入并优先输出 Barrier。如此一来,第一个到达 Barrier 会在算子的缓存数据队列(包括输入 Channel 和输出 Channel)中往前跳跃一段距离,而被”插队”的数据和其他输入 Channel 在其 Barrier 之前的数据会被写入快照中(图中黄色部分)

    什么意思呢?个人理解就是某个Channel中barrier到达了,state的checkpoint就开始执行了,但是这个时候持久化的state信息并不是完整的state,因为其他input channel还有数据没有到达呢!barrier不对齐不能保证数据的一致性!

    那这个时候怎么办呢?不能用阻塞的方式对齐 ,就先把数据存下来,这样也算对齐。就干脆将其他 input  channel中的barrier之前的那些数据也checkpoint下来,这样也能达到barrier对齐的效果。 同时output channel中barrier之后也要checkpoint下来,因为这部分输出的数据无法通过Source重放恢复,所以把输出channel中的数据持久化下来就能规避这个问题。

    通过Input + Output + State三者的持久化,就能在Unaligned Checkpoint语义下实现Exactly_Once语义。

 

step4:

    从方法名称可以看出,先执行state的snapshot,再report执行结果给JobManager。

    taskSnapshotSync方法虽然叫同步,但是执行snapshot的还是还是一个异步执行的过程,该方法只是返回了一个异步执行的FeatureTask。finishAndReportAsync()真正执行FeatureTask,Task执行成功了再进行report,report的消息最终会通过rpc的方式发送CheckpointCoordinator。

    CheckpointCoordinator进行各个SubTask执行结果的确认,将新的completedCheckpoint添加到completedCheckpointStore里,pendingCheckpoints集合中删除对应的checkpoint,最后会调用operator和function的notifyCheckpointComplete,然后各个Operator再执行收尾工作(所谓的二阶段提交)。

snapshot内部会执行callInternal,真正将State写到外部持久化:

 

Flink的二阶段提交图示:

第一个阶段是precommit阶段,就是上面所描述的那全部的一系列流程,直到snapshot state为止,个人理解都算precommit:

    第二阶段就是commit阶段,JobManager收到所有Task发送来的AcknowledgeCheckpoint消息之后,确认snapshot都已经成功,那么就向各个Task发送NotifyCheckPointCompleted消息,进行收尾工作:

    一般的Operator这个地方do nothing,但是Kafka的Comsumer和Producer不太一样。

    Kafka的Consumer在precommit阶段(snapshotstate)是只会进行offset的记录,到了commit阶段(notifyCheckpointComplete())方法中才真正执行offset的提交:

fetcher.commitInternalOffsetsToKafka(offsets, this.offsetCommitCallback);

    Kafka Producer端涉及到事务性的时候就更加复杂了,Kafka的事务性原理可以看我之前写的那篇文章《Kafka的幂等性与事务性理解》。来看下Flink中如何使用Kafka的事务,FlinkKafkaProducer011继承了TwoPhaseCommitSinkFunction。在precommit阶段是初始化事务并创建producer,每个producer分配transactionId,commit阶段执行事务的提交,然后将transactionId回收重复使用,并关闭producer

 

 

Flink1.11 Checkpoint机制适用场景:

    Unaligned Checkpoint由于要持久化缓存数据,State Size 会有比较大的增长,磁盘负载会加重。并且随着 State Size 增长,作业恢复时间可能增长,运维管理难度增加。目前看来,Unaligned Checkpoint 更适合容易产生高反压同时又比较重要的复杂作业。对于像数据 ETL 同步等简单作业,更轻量级的 Aligned Checkpoint 显然是更好的选择。

 

 

PS:checkpint的存储位置

    State Backend状态后端定义了流式应用程序状态如何存储和checkpoint的。不同的状态后端以不同的方式来存储其状态,并且使用不同的数据结构来保存正在运行的应用程序的状态。

    例如,MemoryStateBackend将工作state保存在TaskManager的内存中,并将checkpoint数据存储在JobManager的内存中。后端是轻量级的,没有其他依赖关系,但是可用性不高并且仅支持小状态。

    FsStateBackend将工作state保存在TaskManager的内存中,并将checkpoint数据存储在文件系统中。

    RocksDBStateBackend将工作state保存在RocksDB中,并且默认将checkpoint数据存在文件系统中,类似FsStateBackend。

 

 

参考:

    https://stackoverflow.com/questions/53943989/flink-window-operator-checkpointing(WindowState不会进行checkpoint)

    https://www.pianshen.com/article/5395367077/(Flink CheckPoint流程图)

    https://www.jianshu.com/p/64e8588740e0(Flink State保存位置)

    https://www.jianshu.com/p/762c624591d8(Flink State存储过程)

    https://stackoverflow.com/questions/53943989/flink-window-operator-checkpointing(WindowState是不会进行checkpoint的)

    https://cwiki.apache.org/confluence/display/FLINK/FLIP-76%3A+Unaligned+Checkpoints(Flink1.11 checkpoint新特性官方文档)

    https://developer.aliyun.com/article/768710(Flink1.11 checkpoint新特性介绍)

    https://www.jianshu.com/p/c9d6e9fe900a(Flink1.11 checkpoint流程)

    https://www.jianshu.com/p/e88938b79f91(Checkpoint堆栈)

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值