Apache Flink 概念介绍:有状态流式处理引擎的基石

有状态流式处理(stateful stream processing)

传统批次处理方法

持续收取数据,放到消息队列
周期性划分数据,然后运行一个运算作业(spark/mapreduce)
在这里插入图片描述问题:

要计算一个周期内特地事件转换(A->B)的次数,假如事件A发生在周期1,B发生在周期2,那么这个转换是跨越了所定义的时间划分,很明显这就产生了问题.传统批处理的方法是把中介运算结果带到下一个批次进行计算.除此之外,当出现接收到的事件顺序颠倒情况下,传统批处理仍会将中介状态带到下一批次的运算结果中,这种处理方式也不尽如人意。

理想方法

### 理想方法有状态流式处理两大重点:

1.能够累计并且维护大量的状态,累积状态代表着过去历史中接收过的所有事件,会影响到输出。
2.时间,时间意味着引擎对于数据完整性有机制可以操控,当所有数据都完全接受到后,输出计算结果。
3. 理想方法模型需要实时产生结果,但更重要的是采用新的持续性数据处理模型来处理实时数据,这样才最符合 continuous data 的特性。
在这里插入图片描述

分布式流式处理

假设 Input Streams 有很多个使用者,每个使用者都有自己的 ID,如果计算每个使用者出现的次数,我们需要让同一个使用者的出现事件流到同一运算代码,这跟其他批次需要做 group by 是同样的概念,所以跟 Stream 一样需要做分区,设定相应的 key,然后让同样的 key 流到同一个 computation instance 做同样的运算。
在这里插入图片描述上图每一种颜色代表一个客户,要计算客户使用的次数,那么每一个computational instance(每一个代码运行的作业)负责一种颜色(一类客户)

有状态分布式流式处理

在这里插入图片描述

如图,上述代码中定义了变数 X,X 在数据处理过程中会进行读和写,在最后输出结果时,可以依据变数 X 决定输出的内容,即状态 X 会影响最终的输出结果。这个过程中,第一个重点是先进行了状态 co-partitioned key by,同样的 key 都会流到 computation instance,与使用者出现次数的原理相同,次数即所谓的状态,这个状态一定会跟同一个 key 的事件累积在同一个 computation instance。

第二个重点是 embeded local state backend。有状态分散式流式处理的引擎,状态可能会累积到非常大,当 key 非常多时,状态可能就会超出单一节点的 memory 的负荷量,这时候状态必须有状态后端去维护它;在这个状态后端在正常状况下,用 in-memory 维护即可。

Flink的优势

状态容错

精确一次的容错保证:应用在运算时累积的状态,每笔输入的事件反映到状态,更改状态都是精确一次,如果修改超过一次的话也意味着数据引擎产生的结果是不可靠的。

简单场景的精确一次容错方法

在这里插入图片描述在考虑精确的容错保证前,我们先考虑最简单的使用场景,如无限流的数据进入,后面单一的 Process 进行运算,每处理完一笔计算即会累积一次状态,这种情况下如果要确保 Process 产生精确一次的状态容错,每处理完一笔数据,更改完状态后进行一次快照,快照包含在队列中并与相应的状态进行对比,完成一致的快照,就能确保精确一次.

分布式状态容错

Flink 作为分布式的处理引擎,在分布式的场景下,进行多个本地状态的运算,只产生一个全域一致的快照,如需要在不中断运算值的前提下产生全域一致的快照,就涉及到分散式状态容错。

在这里插入图片描述首先了解一下 Checkpoint,上面提到连续性快照每个 Operator 运算值本地的状态后端都要维护状态,也就是每次将产生检查点时会将它们传入共享的 DFS 中。当任何一个 Process 挂掉后,可以直接从三个完整的 Checkpoint 将所有的运算值的状态恢复,重新设定到相应位置。Checkpoint 的存在使整个 Process 能够实现分散式环境中的 Exactly-once。

在这里插入图片描述关于 Flink 如何在不中断运算的状况下持续产生 Global consistent snapshot,其方式是基于用 simple lamport 演算法机制下延伸的。已知的一个点 Checkpoint barrier, Flink 在某个 Datastream 中会一直安插 Checkpoint barrier,Checkpoint barrier 也会 N — 1 等等,Checkpoint barrier N 代表着所有在这个范围里面的数据都是 Checkpoint barrier N。

在这里插入图片描述
举例:假设现在需要产生 Checkpoint barrier N,但实际上在 Flink 中是由 job manager 触发 Checkpoint,Checkpoint 被触发后开始从数据源产生 Checkpoint barrier。当 job 开始做 Checkpoint barrier N 的时候,可以理解为 Checkpoint barrier N 需要逐步填充左下角的表格。

在这里插入图片描述如图,当部分事件标为红色,Checkpoint barrier N 也是红色时,代表着这些数据或事件都由 Checkpoint barrier N 负责。Checkpoint barrier N 后面白色部分的数据或事件则不属于 Checkpoint barrier N。

在以上的基础上,当数据源收到 Checkpoint barrier N 之后会先将自己的状态保存,以读取 Kafka 资料为例,数据源的状态就是目前它在 Kafka 分区的位置,这个状态也会写入到上面提到的表格中。下游的 Operator 1 会开始运算属于 Checkpoint barrier N 的数据,当 Checkpoint barrier N 跟着这些数据流动到 Operator 1 之后,Operator 1 也将属于 Checkpoint barrier N 的所有数据都反映在状态中,当收到 Checkpoint barrier N 时也会直接对 Checkpoint 去做快照。

在这里插入图片描述当快照完成后继续往下游走,Operator 2 也会接收到所有数据,然后搜索 Checkpoint barrier N 的数据并直接反映到状态,当状态收到 Checkpoint barrier N 之后也会直接写入到 Checkpoint N 中。以上过程到此可以看到 Checkpoint barrier N 已经完成了一个完整的表格,这个表格叫做 Distributed Snapshots,即分布式快照。分布式快照可以用来做状态容错,任何一个节点挂掉的时候可以在之前的 Checkpoint 中将其恢复。继续以上 Process,当多个 Checkpoint 同时进行,Checkpoint barrier N 已经流到 job manager 2,Flink job manager 可以触发其他的 Checkpoint,比如 Checkpoint N + 1,Checkpoint N + 2 等等也同步进行,利用这种机制,可以在不阻挡运算的状况下持续地产生 Checkpoint。

说白了这个表记录了分布式每个节点及其所对应的状态,当发生错误的时候就可以进行恢复

状态维护

状态维护即用一段代码在本地维护状态值,当状态值非常大时需要本地的状态后端来支持。在 Flink 程序中,可以采用 getRuntimeContext().getState(desc); 这组 API 去注册状态。Flink 有多种状态后端,采用 API 注册状态后,读取状态时都是通过状态后端来读取的。Flink 有两种不同的状态值,也有两种不同的状态后端:

  • JVM Heap 状态后端

适合数量较小的状态,当状态量不大时就可以采用 JVM Heap 的状态后端。JVM Heap 状态后端会在每一次运算值需要读取状态时,用 Java object read / writes 进行读或写,不会产生较大代价,但当 Checkpoint 需要将每一个运算值的本地状态放入 Distributed Snapshots 的时候,就需要进行序列化了。

  • RocksDB 状态后端

它是一种 out of core 的状态后端。在 Runtime 的本地状态后端让使用者去读取状态的时候会经过磁盘,相当于将状态维护在磁盘里,与之对应的代价可能就是每次读取状态时,都需要经过序列化和反序列化的过程。当需要进行快照时只将应用序列化即可,序列化后的数据直接传输到中央的共享 DFS 中。

Flink 目前支持以上两种状态后端,一种是纯 memory 的状态后端,另一种是有资源磁盘的状态后端,在维护状态时可以根据状态的数量选择相应的状态后端。

ps:什么叫序列化与反序列化?

对象序列化是一个用于将对象状态转换为字节流的过程,可以将其保存到磁盘文件中或通过网络发送到任何其他程序;从字节流创建对象的相反的过程称为反序列化。而创建的字节流是与平台无关的,在一个平台上序列化的对象可以在不同的平台上反序列化。

扩展:Chandy-Lamport算法
https://zhuanlan.zhihu.com/p/43536305

Event-time

在这里插入图片描述
如图,Event - Time 相当于事件,它在数据最源头产生时带有时间戳,后面都需要用时间戳来进行运算。用图来表示,最开始的队列收到数据,每小时对数据划分一个批次,这就是 Event - Time Process 在做的事情。

在这里插入图片描述具体实现:

Flink 实际上是用 watermarks 来实现 Event - Time 的功能。Watermarks 在 Flink 中也属于特殊事件,其精髓在于当某个运算值收到带有时间戳“ T ”的 watermarks 时就意味着它不会接收到新的数据了。使用 watermarks 的好处在于可以准确预估收到数据的截止时间。举例,假设预期收到数据时间与输出结果时间的时间差延迟 5 分钟,那么 Flink 中所有的 windows Operator 搜索 3 点至 4 点的数据,但因为存在延迟需要再多等 5 分钟直至收集完 4:05 分的数据,此时方能判定 4 点钟的资料收集完成了,然后才会产出 3 点至 4 点的数据结果。这个时间段的结果对应的就是 watermarks 的部分。

状态保存与迁移

Checkpoint 完美符合以上需求,不过 Flink 中还有另外一个名词保存点(Savepoint),当手动产生一个 Checkpoint 的时候,就叫做一个 Savepoint。Savepoint 跟 Checkpoint 的差别在于检查点是 Flink 对于一个有状态应用在运行中利用分布式快照持续周期性的产生 Checkpoint,而 Savepoint 则是手动产生的 Checkpoint,Savepoint 记录着流式应用中所有运算元的状态。

在这里插入图片描述如图,Savepoint A 和 Savepoint B,无论是变更底层代码逻辑、修 bug 或是升级 Flink 版本,重新定义应用、计算的平行化程度等,最先需要做的事情就是产生 Savepoint。

Savepoint 产生的原理是在 Checkpoint barrier 流动到所有的 Pipeline 中手动插入从而产生分布式快照,这些分布式快照点即 Savepoint。Savepoint 可以放在任何位置保存,当完成变更时,可以直接从 Savepoint 恢复、执行。

从 Savepoint 的恢复执行需要注意,在变更应用的过程中时间在持续,如 Kafka 在持续收集资料,当从 Savepoint 恢复时,Savepoint 保存着 Checkpoint 产生的时间以及 Kafka 的相应位置,因此它需要恢复到最新的数据。无论是任何运算,Event - Time 都可以确保产生的结果完全一致。

假设恢复后的重新运算用 Process Event - Time,将 windows 窗口设为 1 小时,重新运算能够在 10 分钟内将所有的运算结果都包含到单一的 windows 中。而如果使用 Event – Time,则类似于做 Bucketing。在 Bucketing 的状况下,无论重新运算的数量多大,最终重新运算的时间以及 windows 产生的结果都一定能保证完全一致。

总结

在这里插入图片描述

ref

https://mp.weixin.qq.com/s/oBmRhRA-52CLRLXp6sZwEw

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值