本文主要介绍Flink的检查点及故障恢复机制。了解Flink是如何提供精确一次的状态一致性保障的。另外还会介绍Flink独有的保存点机制。
一、checkpoint
checkpoint机制是Flink可靠性的基石,可以保证Flink集群在某个算子因为某些原因出现故障时,能够将整个应用流图的状态恢复到故障之前的某一状态,保证应用流图状态的一致性。
用一个简单的实现算法来解释应用建立一致性检查点的过程,概括的将这个简单算法的步骤就是:
暂停应用 --> 等待流入数据被全部处理,将全部任务状持久化存储,生成检查点 --> 再重新恢复应用
当然,Flink并没有实现这种简单算法,而是使用了一种更加复杂的检查点算法,具体在下面Checkpoint原理一节中细讲。
二、从checkpoint中恢复状态
在执行流应用程序期间,Flink 会定期保存状态的一致检查点。如果发生故障, Flink 将会使用最新的检查点将应用恢复到某个一致性的点,并重新启动处理流程。
应用的恢复需要经历三个步骤:
-
重启整个应用;
-
利用最新的检查点重置任务状态;
-
恢复所有任务的处理。
注意:只有所有输入流都是来自于可重置的数据源,应用才支持精确一次的状态一致性。比如,Apache Kafka可以,但是Socket消费就不行。
三、checkpoint原理
如上第一节讲述的简单算法那样“停止一切”的行为,对于具有低延迟要求的应用中就显得很不切实际。Flink也并没有这要做,Flink的检查点则基于Chandy-Lamport分布式快照算法来进行实现。这种算法把生成检查点和处理过程进行了分离,这样做就不用上面简单算法那样停止整个应用。
1、检查点分隔符
在Flink检查点算法中有一个特殊记录——检查点分隔符(checkpoint barrier)。barrier会通过数据源算子注入到数据流中,随着数据流一起流动,但位置不会提前或延后。每个barrier会带一个检查点编号,这样就把数据流从逻辑上分成了两个部分:
- 先于分隔符的记录所引起的状态更改会被包含在分隔符所对应的检查点中;
- 晚于分隔符的记录所引起的状态更改会被包含在之后的检查点中。
2、检查点生成过程
我们通过一个示例一步一步的来解释这个Flink生成检查点的算法过程。如下图:两条自增的数据流,流动过程被分为奇数流和偶数流,并各自求和,将结果更新至下下游。
应用执行过程中,JobManager会向每个Source任务发送一条带有新检查点ID的消息(如下图蓝色三角块),通过这种方式来启动检查点。
紧接着,source算子利用状态后端触发生成本地状态的检查点,并将检查点分隔符连同检查点编号向下游广播(这个检查点就是实现Chandy-Lamport分布式快照算法的核心);当状态后端在状态存入检查点之后,会返回通知给source算子,source算子就会向JobManager确认检查点完成。
当其中一个Sum算子收到一个新检查点的分隔符时,会继续等待所有其它输入分区也发来这个检查点分隔符。这个等待的过程中,会出现两种处理情况:
- 对于分隔符已经到达的分区,继续到大的数据会被缓存起来(如下图,蓝色圆4);
- 对于分隔符没有到达的分区,数据会被继续处理;
在Sum算子收齐全部输入分区发送的分隔符后(如下图橙色蓝色三角2),就会通知状态后端开始生成检查点(下图数字8),同时把检查点分隔符(橙色蓝色三角2)广播到下游相连的算子。
等到Sum算子发出所有的检查点分隔符后就会开始处理缓存的记录。等处理完缓存的记录后,再继续处理输入流。
最后,检查点分隔符到达Sink算子。Sink算子收到分隔符后,会向JobManager确认状态保存到检查点。当所有任务都确认已成功将状态保存到检查点时,就会将此次检查点标记为完成。
为此,当应用在发生故障时就可以利用这个生成好的检查点进行恢复了。
四、save points
-
Flink 还提供了可以自定义的镜像保存功能,就是保存点(savepoints);
-
原则上,创建保存点使用的算法与检查点完全相同,因此保存点可以认为就是具有一些额外元数据的检查点;
-
Flink不会自动创建保存点,因此用户(或外部调度程序)必须明确地触发创建操作;
-
保存点是一个强大的功能。除了故障恢复外,保存点可以用于:有计划的手动备份,更新应用程序,版本迁移,暂停和重启应用,等等。