Flink Checkpoint 原理机制详解
Flink Checkpoint 原理机制详解
Flink的Checkpoint机制是其核心功能之一,用于实现流式应用的故障恢复。本文将从基本概念出发,逐步深入讲解Checkpoint的实现原理,包括单机和多机场景下的处理方式,并提供具体的代码配置示例。
一、什么是 Checkpoint?
Checkpoint是对当前运行状态的完整记录。程序重启后能从Checkpoint中恢复出输入数据读取到哪了,各个算子原来的状态是什么,并继续运行程序。即用于Flink的故障恢复。这种机制保证了实时程序运行时,即使突然遇到异常也能够进行自我恢复。
二、如何实现 Checkpoint 功能?
如果让你来设计,对于流式应用如何做到故障恢复?我们从最简单的单机单线程看起。
一)单机情况
同步执行,每次只处理一条数据
很简单,这种情况下,整个流程一次只处理一条数据。
- 数据到Write阶段结束,各个算子记录一次各自状态信息(如读取的offset、中间算子的状态)
- 遇到故障需要恢复的时候,从上一次保存的状态开始执行
- 当然为了降低记录带来的开销,可以攒一批之后再记录。
同时处理多条数据
每个计算节点还是只处理一条数据,但该节点空闲就可以处理下一条数据。如果还按照一个数据Write阶段结束开始保存状态,就会出现问题:
- 前面节点的状态,在处理下一个数据时被改过了
- 从此时保存的记录恢复,前面的节点会出现重复处理的问题
- 此时被称为-确保数据不丢(At Least Once)
一种解决方式:
- 在输入数据中,定期插入一个barrier。
- 各算子遇到barrier就开始做状态保留,并且不再接收新数据的计算。
- 当前算子状态保留后,将barrier传递给下一个算子,并重复上面的步骤。
- 当barrier传递到最后一个算子,并完成状态保留后,本次状态保留完成。
这样,各个节点保存的都是相同数据节点时的状态。故障恢复时,能做到不重复处理数据,也就是精确一次(Exactly-once)。
但这里,你可能会发现一个问题:
- 数据已经写出了怎么办?在两个保存点之间,已经把结果写到外部了,重启后不是又把部分数据再写了一次?
这里实际是「程序内部精确一次」和「端到端精确一次」。那么如何做到「端到端精确一次」? - 方案一:最后一个sink算子不直接向外部写出,等到barrier来了,才把这一批数据批量写出去
- 方案二:两阶段提交。需要sink端支持(如kafka)。
- 方式类似于MySQL的事务。
- sink端正常向外部写出,不过输出端处于pre-commit状态,这些数据还不可读取
- 当sink端等到barrier时,将输出端数据变为committed,下游输出端的数据才正式可读
不过以上方法为了做到端到端精确一次,会带来数据延迟问题。(因为要等Checkpoint做完,数据才实际可读)。解决数据延迟有一种方案: - 方案:幂等写入。同样一条数据,无论写入多少次对输出端看来都是一样的。(比如按照主键重复写这一条数据,并且数据本身没变化)
二)重要概念介绍
一致性级别
前面的例子中,我们提到了部分一致性级别,这里我们总结下。在流处理中,一致性可以分为3个级别:
- at-most-once(最多一次): 这其实是没有正确性保障的委婉说法——故障发生之后,计数结果可能丢失。
- at-least-once (至少一次): 这表示计数结果可能大于正确值,但绝不会小于正确值。也就是说,计数程序在发生故障后可能多算,但是绝不会少算。
- exactly-once (精确一次): 这指的是系统保证在发生故障后得到的计数结果与正确值一致。恰好处理一次是最严格的保证,也是最难实现的。
按区间分: - 程序(Flink)内部精确一次
- 端到端精确一次
Checkpoint 中保留的是什么信息?
🤔 如果是你来设计,checkpoint都需要保留哪些信息,才能让程序恢复执行?
【这里说的就是state】
考虑一个开发需求:单词计数。从kafka中读数据,处理逻辑是将输入数据拆分成单词,有一个map记录各个单词的数量,最后输出。
- 从输入流中,拆分单词
- 将统计的结果放到内存中一个Map集合,单词做为key,对应的数量做为value
想要恢复的时候还能接着上次的状态来,要么就需要几个信息: - 处理到哪条数据了
- 中间状态是啥
- 数据写出到哪条了
以及,上述信息应是针对同一条数据的。否则状态就乱了。那么可以得到,保留的信息是:
source 中间算子 sink
已输入的数据(offset) [<hello, 5>, <world, 10>, ...] 写出到第几条了
三)多机多进程
随着业务的发展,单机已经不能满足需求了,开始并行分布式的处理。读取、处理、写出,也不再是一个进程从头到尾干完,会拆分到多个机器上执行。也不再等待一条数据处理完,才处理下一条。多机多线程,问题就开始变得复杂起来:
- 如何确保状态拥有精确一次的容错保证?
- 如何在分布式场景下,替多个拥有本地状态的算子产生一个全域一致的快照?
- 对于流合并,合并节点会受到多个barrier 如何处理?
- 如何在不中断运算的前提下产生快照?
🤔 先思考下,如果还用单线程中barrier的方式处理。会遇到什么问题,该如何解决?
处理流程
我们还是在数据流中插入barrier。
- 到达第一个source节点和之前的没区别,source节点开始保存状态(offset)
- 接下来,source将barrier拆分为两个,分别发往下游的算子
- 下游算子收到barrier,开始记录状态
- 关键是最后的operator#2,它会收到多个barrier
- barrier的初始目的是,收到barrier表示前面的数据都处理完了,要开始保存状态了
- 两个绿色的节点(operator#1)分别发送barrier,代表两个barrier之前处理过的数据,实际都是第一个蓝色节点(source)barrier之前的数据。
- 那么最后的橙色节点(operator#2),理应收到所有由绿色节点(operator#1)发送的barrier,才代表数据已经收全了,可以开始保存状态。【叫做barrier对齐】
对于多分支合并的情况,在等待所有barrier到齐的过程中:
- 先收到barrier的分支,还会有数据不断流入
- 为了能做到精确一次(Exactly-once),就不能处理这些数据,需要先缓存起来,否则这个节点的状态就不对了
- 上面一条反过来说,如果不等,直接处理,那么就是至少一次(At Least Once)的效果。(想想在故障恢复的时候,是不是就会重复计算了)
如何在不中断运算的前提下产生快照?
前面做快照,我们假设的是节点收到barrier后,就不再接收新数据,把当前节点状态保存后,再接收新数据,然后把barrier再向后传递。那,是否必须这样串行来呢?
- 卡住新数据,保存当前状态,这里必须串行,不串行状态就乱了
- 但是,向后发送barrier可以同时做,不影响当前节点的保存
那,后面节点保存完了,前面节点还没保存完怎么办? - 没关系,一次checkpoint成功,需要等待所有节点都成功才行,保存的先后顺序无所谓
三、Flink Checkpoint 配置
程序中如何开启 checkpoint
StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
// 开启 checkpoint,并设置间隔 ms
env.enableCheckpointing(1000);
// 模式 Exactly-Once、At-Least-Once
env.getCheckpointConfig().setCheckpointingMode(CheckpointingMode.EXACTLY_ONCE);
// 两个 checkpoint 之间最小间隔
env.getCheckpointConfig().setMinPauseBetweenCheckpoints(500);
// 超时时间
env.getCheckpointConfig().setCheckpointTimeout(60000);
// 同时执行的 checkpoint 数量(比如上一个还没执行完,下一个已经触发开始了)
env.getCheckpointConfig().setMaxConcurrentCheckpoints(1);
// 当用户取消了作业后,是否保留远程存储上的Checkpoint数据
env.getCheckpointConfig().enableExternalizedCheckpoints(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION);
checkpoint 存储
Flink开箱即用地提供了两种Checkpoint存储类型:
- JobManagerCheckpointStorage:将Checkpoint快照存储在JobManager的堆内存中
- FileSystemCheckpointStorage:放到HDFS或本地磁盘中
四、小结
本节介绍了FlinkCheckpoint故障恢复机制。从单机单线程,到多机多线程一步步分析如何实现状态保存和故障恢复。同时对一致性级别进行了探讨,对程序内部和端到端一致性的实现方式给出了可行的方案。后续会对Checkpoint程序内部实现原理进行剖析。
参考文章:
- Flink Checkpoint 深入理解-CSDN博客
- 漫谈 Flink - Why Checkpoint - Ying
- Flink之Checkpoint机制-阿里云开发者社区(图不错)
- Flink 状态一致性、端到端的精确一次(ecactly-once)保证 - 掘金
- 硬核!八张图搞懂 Flink 端到端精准一次处理语义 Exactly-once(深入原理,建议收藏)-腾讯云开发者社区-腾讯云