flink checkpoint源码分析一

25 篇文章 0 订阅
16 篇文章 4 订阅

FlinK CheckPoint 是程序故障恢复以及数据一致性的效果的基础,checkpoint是一种分布式快照:对一个Flink作业的所有task做一个快照且将快照保存在 memory / file system 等存储系统中。这样,在任务进行故障恢复的时候,就可以还原到任务故障前最近一次检查点的状态,从而保证数据的一致性。当然,为了保证 exactly-once / at-least-once 的特性,还需要数据源支持数据回放。

概述
flink的checkpoint 机制基于 chandy-lamda 算法,具体的实现可以参考Flink 官方的文档以及 Flink 团队发表的论文 State Management in Apache Flink。这里先做一下概要性的介绍。
Flink 分布式快照的核心在于 stream barrier,barrier 是一种特殊标记的消息,它会作为数据流的一部分和数据一起向下流动。barrier不会干扰正常的数据,数据流严格有序。一个barrier 把数据流分割成两部分;一部分进入当前的快照,**另一部分进入下一个快照。每一个barrier都带有快照ID,并且 barrier 之前的数据都进入了此快照。barrier 不会干扰数据流处理。所以很轻量。多个不容快照的多个barrier 会在流中同时出现。即多个快照可能同时创建。**而当一个operator 从它所有的input channel 中都收到barrier,则会触发当前operator的快照操作,并且向其下游channel 中发射barrier。当所有的sink 都反馈完成快照之后,Checkpoint coordinator 认为检查点创建完毕。详细流程参考下图:
在这里插入图片描述
在这里插入图片描述

具体步骤为:

一、checkpoint 的流程发起

CheckpointCoordinator 是flink 分布式快照流程的协调者, 它主要负责:
(1)、发起checkpoint 触发的消息,并接收不同task 对checkpoint 的响应信息(ack)
(2)、维护 Ack 中附带的状态句柄(state-handle)的全局视图

1、在任务初始化的过程中,也就是在StreamingJobGraphGenerator 任务图的生产过程中会调用configureCheckpointing 方法进行 Checkpoint 相关的配置。
其中会初始化三个列表,分别存储 任务节点其中, triggerVertices 只包含那些作为 source 的节点,ackVertices 和 commitVertices 均包含所有的节点:
在这里插入图片描述

2、在ExecutionGraphBuilder#buildGraph 任务执行树过程中,如果作业开启了checkpoint,则会调用ExecutionGraph.enableCheckpointing() 方法, 这里会创建 CheckpointCoordinator 对象,并注册一个作业状态的监听 CheckpointCoordinatorDeActivator, CheckpointCoordinatorDeActivator 会在作业状态发生改变时得到通知。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
当状态变为RUNNING时,CheckpointCoordinatorDeActivator会得到通知并且通过 checkpointCoordinator.startCheckpointScheduler 启动 checkpoint 的定时器。
在这里插入图片描述
定时任务并封装成 ScheduledTrigger,运行时会调用CheckpointCoordinator.triggerCheckpoint() 触发一次checkpoint。checkpointCoordinator.triggerCheckpoint 的代码逻辑很多,可以概况为以下几个步骤
1)检查是否可以触发checkpoint,包括是否需要强制进行checkpoint.当前排队的checkpoint的数码是否超过阈值,距离上一次成功checkpoint的间隔时间是否过小等,如果这些条件不满足,则当前检查点的触发请求不执行 具体参考 CheckpointTriggerResult 方法
2)、检查是否所有需要触发 checkpoint 的 Execution 都是 RUNNING 状态**(此时就遇到source 并行度设置过大 checkpoint 失效的问题)**
3)、生成此次 checkpoint 的 checkpointID(id 是严格自增的),并初始化CheckpointStorageLocation,CheckpointStorageLocation 是此次 checkpoint 存储位置的抽象,通过 CheckpointStorage.initializeLocationForCheckpoint() 创建(CheckpointStorage 目前有两个具体实现,分别为 FsCheckpointStorage 和 MemoryBackendCheckpointStorage),CheckpointStorage 则是从 StateBackend 中创建
4)、生成 PendingCheckpoint,这表示一个处于中间状态的 checkpoint,并保存在 checkpointId -> PendingCheckpoint 这样的映射关系中
5)、注册一个调度任务,在在 checkpoint 超时后取消此次 checkpoint,并重新触发一次新的 checkpoint
6)、调用 Execution.triggerCheckpoint() 方法向所有需要 trigger 的 task 发起 checkpoint 请求

注意:savepoint 和checkpoint 的处理逻辑基本一致,只是savepoint是强制触发的,需要调用Execution.triggerSynchronousSavepoint() 进行触发。并且在checkpointCoordinator 内部也有三个列表

ExecutionVertex[] tasksToTrigger;
ExecutionVertex[] tasksToWaitFor;
ExecutionVertex[] tasksToCommitTo;

这就对应了前面JobGraph 中的三个列表,在触发checkpoint的时候,只有作为source的Execution会调用Execution.triggerCheckpoint() 方法。会通过RPC调用通知对应的RpcTaskManagerGateway 调用 triggerCheckpoint。
在这里插入图片描述
在这里插入图片描述

二、checkpoint 的执行流程

1、barrier 的流动
CheckpointCoordinator 发出触发checkpoint的消息,最终通过调用RPC调用TaskExecutorGateway.triggerCheckpoint,即请求执行TaskExecutor.triggerCheckpoin()。因为一个TasKExecutor中可能有多个Task正在运行,因而要根据触发chekpoint 的ExecutionAttemptID 找到对应的Task,然后调用Task.triggerCheckpointBarrier() 方法。因为作为source的Task 才会触发triggerCheckpointBarrier() 方法的调用。
在Task 中,checkpoint 的触发被封装为一个异步任务执行。
在这里插入图片描述
在这里插入图片描述

![在这里插入图片描述](https://img-blog.csdnimg.cn/202009221530138.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3dlaXhpbl80MDgwOTYyNw==,size_16,color_FFFFFF,t_70#pic_center在这里插入图片描述
2、其中Task执行checkpoint 的真正逻辑被封装在AbstractInvokable.triggerCheckpoint(…)中,AbstractInvokable 中有两个触发checkpoint 的方法 triggerCheckpoint 和triggerCheckpointOnBarrier
其中triggerCheckpoint 是触发checkpoint 的源头,会想下游注入CheckpointBarrier;而下游的其他任务再收到checkpointBarrier 后调用triggerCheckpointOnBarrier 方法。这两个方法的具体实现有一些细微的差异,但主要的逻辑是一致的。在StreamTask.performCheckpoint() 方法中
1)、先向下游发送barrier
2)、存储检查点快照

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
3、我们知道,每个task 通过InputGate 消费上游 Task 产生的数据,而实际上在StreamInputProcessor 和 StreamTwoInputProcessor 中会创建 CheckpointBarrierHandler, CheckpointBarrierHandler是对InputGate的一层封装,这其中增加了对CheckpointBarrier等事件的处理。而其中CheckpointBarrierHandler有两个具体的实现,即 BarrierTracker 和 BarrierBuffer,分别对应 AT_LEAST_ONCE 和 EXACTLY_ONCE 这两种模式。
StreamInputProcessor 和 StreamTwoInputProcessor 循环调用CheckpointBarrierHandler.getNextNonBlocked() 获取新数据,因而在CheckpointBarrierHandler 获得 CheckpointBarrier 后可以及时地进行 checkpoint 相关的操作。
下面 我们来看下 AT_LEAST_ONCE 模式下的 BarrierTracker,他的处理逻辑是仅仅追踪从每一个input channel 接收到的 barrier,当所有的input channel 的barrier 都被接收了,就可以触发checkpoint 了。
(注意此处参考flink1.6 版本,flink1.9 对此处做了升级)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
4、而对于EXACTLY_ONCE 模式下的BarrierBuffer,它除了要追踪每一个input channel 接收到的barrier之外,在接收到的所有的barrier之前,先将收到的barrier的channel 要进入到阻塞状态,当然味蕾避免进入’反压‘状态,BarrierBuffer 会继续接收数据,但会对接收到的数据进行缓存。直到所有的barrier都到达。

@Override
	public BufferOrEvent getNextNonBlocked() throws Exception {
		while (true) {
			// process buffered BufferOrEvents before grabbing new ones
			Optional<BufferOrEvent> next;
			if (currentBuffered == null) {
				next = inputGate.getNextBufferOrEvent();
			}
			else {
				next = Optional.ofNullable(currentBuffered.getNext());
				if (!next.isPresent()) {
					completeBufferedSequence();
					return getNextNonBlocked();
				}
			}

			if (!next.isPresent()) {
				if (!endOfStream) {
					// end of input stream. stream continues with the buffered data
					endOfStream = true;
					releaseBlocksAndResetBarriers();
					return getNextNonBlocked();
				}
				else {
					// final end of both input and buffered data
					return null;
				}
			}

			BufferOrEvent bufferOrEvent = next.get();
			if (isBlocked(bufferOrEvent.getChannelIndex())) {
				// if the channel is blocked we, we just store the BufferOrEvent
				bufferBlocker.add(bufferOrEvent);
				checkSizeLimit();
			}
			else if (bufferOrEvent.isBuffer()) {
				return bufferOrEvent;
			}
			else if (bufferOrEvent.getEvent().getClass() == CheckpointBarrier.class) {
				if (!endOfStream) {
					// process barriers only if there is a chance of the checkpoint completing
					processBarrier((CheckpointBarrier) bufferOrEvent.getEvent(), bufferOrEvent.getChannelIndex());
				}
			}
			else if (bufferOrEvent.getEvent().getClass() == CancelCheckpointMarker.class) {
				processCancellationBarrier((CancelCheckpointMarker) bufferOrEvent.getEvent());
			}
			else {
				if (bufferOrEvent.getEvent().getClass() == EndOfPartitionEvent.class) {
					processEndOfPartition();
				}
				return bufferOrEvent;
			}
		}
	}

除了 CheckpointBarrier 消息以外,在 checkpoint 发生异常或取消 checkpoint 的时候,会向下游发送 CancelCheckpointMarker 消息。

flink checkpoint 源码分析二
https://blog.csdn.net/weixin_40809627/article/details/108735766

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值