开发者学堂课程【Apache Flink 入门到实战 - Flink 开源社区出品 :Apache Flink 概念介绍:有状态流式处理引擎的基石(二)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/632/detail/10037
Apache Flink 概念介绍:有状态流式处理引擎的基石(二)
五.有状态流式处理的挑战
这部分包括状态容错,状态维护,Event-time 处理,还有状态保存与迁移,这四个点都是身为一个状态,流式处理引擎必须有的特征,如果没有这些特征,以现在来说应是比较不成熟的。
1.状态容错
一提到状态这个东西,当引擎去维护状态,就一定会想知道,如果节点挂了,引擎会如何做到状态容错。所以考虑状态容错,一定会想要考虑的就是精确的状态容错。
就是一个应用在运算的时候累积状态,通常情况下一定会希望每一笔输入的事件反映到状态,更改状态都是恰好一次,精确到一次。
如果更改超过一次的话,就代表这一个数据引擎产生的结果是不可靠的。
同理,用刚刚很简单的 counter,就是使用者拜访的次数来看的话,如果某一个使用者拜访的次数多计算了,并不是精确一次的话,那所产生的结果也是没办法参考的。
首先考虑最简单的一个使用场景,先考虑的是有一个无穷无尽的 q,data 一直在进来,数据进来后单一个执行绪的 process 预算就可以,
此时状态也是不断累积的。
产生一个精确一次的容错方法的做法其实很简单,那就是每处理完一笔,更改完状态之后,都做一个快照,快照会包含它在 Q 里面的位置、处理到第几笔以及当时的状态。
如图做一个对比,做个一致的快照,在这个四档图里面,当处理到第二笔时就可以把它想成位置是 X,对应到状态 state X,如果现在进展到接下来这一笔,所处位置也就跟着更新了,状态也更新,每处理完一笔就做一个这样的快照。
假设在处理下一笔时,这一笔造成 process 失败了,如果要 recover 确保进去一次,只需拿上一个的位置与上一个状态直接回复就可以。
接下来,就要学习如何在分散式场景下,替多个拥有本地状态的运算子产生一个全域一致的快照,更重要的是如何在不中断的运算前提下产生快照。
通常情况下可以作用笨的方法,也可以用好的方法去完成。首先定义什么叫 global consistent snapshot,就是图中这些 operator,在分散式的环境中,在各个节点去做运算。
第一个方法是处理完一笔快照后,再更改运算值状态,更改完所有的运算值的状态后,目前所看到的每一个运算值状态,只是刚刚讲的简易场景的延伸而已,到这里其实就可以想到笨的方式是什么,就是让每一笔每个运算值之后产生一个快照,然后再让第二笔经过所有的 operator 再产生一个快照,这个比较笨的方式会有一个负作用,就是每出完一笔到第二个 operate 之后,其实第一个 operator 是可以继续做运算的,可是已经停止了所有之前的 operator 的运算,运算中断后使用者也会付出相应的代价。
这里要介绍一个词,就是 checkpoint,目前 flink 社区里面将 checkpoint 翻译成检查点。
每一个 operator,每个预算值他本地后端所维护的这个状态,会在每一次产生一个检查点的时候把他们传到一个共享的 DFS,即使任何一个 process fail 掉时,也可以直接从上一个完整的检查点去把所有的预算值的 state 的状态恢复,然后再把试用卡数据源,就是把卡的位置直接重新设定到对的位置,那利用这样才有办法去达到 XXY,在一个分散式的环境中。
其中,刚刚一些提示的重点,就是系统如何在不中断运算的状况下持续产生,其实就是基于一个之前颜色法机制去延伸出来的方法。
那先知道一个点,一个 part of barrier,它会在 data stream 中一直去安插 checkpoint barrier,然后 checkpoint barrier 会出现 N- 或 N。
如上图,假设现在需要产生 checkpoint barrier,但实际上在 think 中是由 job manager 去触发 checkpoint,在触发 checkpoint 之后就会从数据源开始,由checkpoint barrier 去填满一个表格,如图左下角。
把下面的这一些事件标为红色,checkpoint barrier 也是红色,这个代表着这些数据,这些事数据事件都是属于其负责的 triple berry2,后面的这些白色的就不属于Barry n 项的概念数据源收到了触碰 Barry N 之后,他会先去把状态保存,那数据源的状态,就会是目前 competition 的位置。
这个状态会写在刚刚做的表格之中,同时下游的 operator won 运算之一,也会开始去运算,这些属于 triple Berry n 的数据。那当 triple Berry n 跟着这些数据慢慢的流动 OPERATOR1 运算之后,就会变成是预算之一,也把属于 checkpoint berry 的所有的资料也都反映在状态里面的跟踪状态。
这时候收到 triple berry 也会去直接对 checkpoint 去做,继续往下游,OPERATOR2 也会收到所有数据,然后直接反映到状态。
到这一步已经完成了一个完整的表格,其实这个表格叫做 distributed snapshots,完整的表格就可以被用做容错。
2. 状态维护
第二个内容是状态维护。状态维护刚才讲到就是写一段程式码,这段程式码可以去维护本地的一些状态值,如果状态值很大的话,一定要有本地的状态后端。
上图重点就是状态可能是非常非常大的,那我这个状态后端要么就是 memory,要么就是 out of course 去处理维护这些状态。
那所以说 Flink 有两种不同的状态值,有两种不同的状态后端。第一个就是 JPMP 的状态后端,这种状态后端是状态量不会有那么大的。就可以只用 JBNP 的状态后端。
第二个选择就是 rocksdb 的状态户端,意为在 runtime 的 local 本地状态后端,在让 user code 使用者读取这些状态的时候,都是可以经过维护。
代价就是每一次需要去读取状态的时候,都需要经过一个序列化反序列化的过程。相对来说现下要进行快照的产生的时候,其实就变成了只是用东西的序列化,那些序列化好的东西直接就是传输到中央共享 DFS。
3. Event-time 处理
在 FLINK 或者一些比较进阶的方式出现之前,都只有 processing time 的处理,所谓的 processing time 处理,假设需要定义一个窗口,预算一个 window 的competition,而且 window competition 需要低于三点到四点,然后也可以说 window 的 operation 定义就是每一个小时进行结算。
那其实以 processing time 在做这件事情的运算,就会变成是这个数据引擎所在三点到四点收到的资料去做个结算。可是,实际上人们在去做一些报表或者做任何一条去产生这些分析的结果的时候,是想要知道真实世界中三点到四点真的发出去的资料。
那如果要做这样的运算的话,就必须用 even time。在这个图中,Even time 等于说是这个事件真的在数据最远投产生的时候,用时间进行运算。
那上图表示中最开始的 Q,收到的资料,利用每一个小时去划分一个批次,把对应的时间例如三点到四点的数据,真的把它放到三点到四点的一个 bucket,然后这个bucket 接着去产生结果。
假设有一个 window operator 正在做预算,每一个小时产生结果,要如何清晰表明这个 window 的运算,只说四点该收的资料都已经收到了,可以产生结果了。
这个问题的回答的背后其实就是 operator 必须要知道四点到了,这里的四点到了,是指 event 事件的四点到了,那这个就是 EVEN TIME 处理的精髓。
Watermark ,水位线。现在有个预算值,会收到某一个带有时间,water mark代表运算值,它可以预期不会再收到更早的资料。好处在于预期的数据如果真的收到,却与产生出的时间差都是五分钟,这时候就会想这个过程中最慢就是推迟5分钟,这时候可能产生 water mark delay5 分钟。
推迟5分钟之后,接下来里面的所有的 window operator 收到四点的资料了,可是若知道再多等五分钟,等到四点零五分时才可以判定四点的资料全部收集完毕。
4. 状态保存与迁移
流式处理应用是无时无刻在运行维运上有几个重要考量,
(1)如何更改 bug 等或如何将前一执行的状态转移到新的执行?
(2)如何定义运行的平行化程度?
(3)如何升级运算从级的版本号?
上图的保存点可以完美满足以上的需求。Flink 中有另外一个词,若今天是手动产生一个检查点的时候,其实叫做一个保存点,英文是 save point,目前的翻译叫做保存点,这与检查点的差别就是检查点是 Flink,对于一个有动态应用在运行中,会一直周期性的产生,利用 Distribute a snapshot 的方式,周期性的产生这些检查点。保存点就是手动去更新,保存点记录着流逝应用中所有运算元的状态。
在使用过程中,首先在执行停止之前,要新建一个保存点,执行完上述条件后,从保存点恢复新的执行,并且利用 even time 处理赶上最新的数据。如果运算结果包含在单一 window 里,产生的结果就无法保持完全一致。
六.总结
1.状态容错: 精确一次保证,分布式快照(Distributed Snapshots)。
2. 可应付极大的状态t (TB+ scale): out-of-core 状态后端,asynchronous 快照。
3. 状态迁移:在应用重新平行化/更动应用代码的状况下仍能恢复历史状态。
4. Event-time 处理:用以定义何时接收完毕所需数据。