Spark Structured Streaming 与 Flink不同的checkpoint实现方式(上)

这篇文章将分为上下两篇, 上篇理论, 下篇源代码。将讲解一下checkpoint在spark和flink里面的实现方式, 以及大概为什么要这样实现, 这里只讨论实时系统,别的不包括在内。

为什么要有checkpoint

对于一个实时处理系统来说, checkpoint是必不可少的,用做容错时恢复的依据。

理论

例如这样一个系统, 怎么样用checkpoint来表达这个系统的状态:

也就是说, 当我们input是流数据的时候,我们整个系统的状态将由所有的边 和 所有的算子的状态集合来表示

例如说当你想表达input为1,2,3,4,5的数据流时,有可能元素1,2,3此时还在网络传输过程中, 元素4,5已经在operator中,这时整个系统的状态S就包括了所有的数据(在网络中的1,2,3 和已经到达operator中的4,5)

trade off

先说结论:

边的状态要为空!也就是说边不可以有状态, 系统的状态只能由Operator的状态来表达!

原因:

checkpoint的作用是在出错时回放这个整个过程, 并保证系统内的一致性, 如果整个系统集合内的状态是包含StateOfEdge(边的状态)的话, 对于系统回放来说, 基本是不可能的, 因为元素在边上只是一个抽象的说法, 具体举个例子就是, 输入元素有可能在网线上以高低电平传输, 也可能正在以光信号传输, 也可能正在网卡缓冲区里, 也能在内核缓冲区。很难回放出来一个网线里1,2,3正在传输, 4,5已经在operator状态里的系统。

目标:

边没有状态, 所有状态都在operator里, 说得白一点就是, 没有数据正在传输, 数据都在用户态的operator里。

怎么做

还是说白一点, 怎么保证数据都已经处理完了, 没有任何一条数据在传输过程中, 或者遗留在边里。

输入边界确定的系统

如果说输入确定的话,计算也确定的话, 输出端是可以确定所有元素都处理完成(也就是说可以确定,所有边是没有状态的。例如输入端是1,2,3,4,5,计算是求average, 输出端明确知道, 数据集大小是1,2,3,4,5,当输出端的算子收到1,2,3,4,5时, 就可以明确边是没有状态的, 此时的checkpoint中输出端算子的average=3, 就表达了输入1,2,3,4,5的状态。

这个时候点下题, Spark是基于微批处理的,每一个批次的输入的确定的, 计算也是确定的, 所以checkpoint在每个batch结束都会将状态写出到外部存储里面,这样的checkpoint是可以表达整个流系统的状态的。

输入边界不确定的系统

问题就变成了, 我们做checkpoint的时候, 怎么确定,某个边上没有状态(没有元素)?我们可以输入一个特殊标志, 当下游收到这个标志的时候, 就可以明确了, 在这个特殊标志之前的元素都不在边上。例如x --> 1 -->2 是我们的输入, 当下游收到x的时候, 就可以确定, 之前的1 --> 2都已经不在边上了。 这也就是Flink的checkpoint的做法。这里的特殊标志也就是Flink里的Barrier, 看到这里大家可以再多想一会, 应该就能理解了为什么Flink里的partition要等到所有Barrier到齐,再做checkpoint了(因为要等到所有边的状态都是空, 注意那个公式里的Sigma符号)。

结尾

我个人文笔比较差, 没法写出像很多爆火文章里的那种讲故事类型的文章。 写文章只是为了我个人理清思路, 也是为了践行一下开源的精神。毕竟分享知识也是也是一种开源的精神,如果文章有什么写的不好的地方,或者可以改进的地方,可以留言。但我文章估计也没啥人看。。。 如果真有人看到这里的话,希望对你有点帮助。

我来评几句
登录后评论

已发表评论数()

相关站点

+订阅
热门文章