flink状态state
这一章挺难的,尤其是分布式快照的思想,如果想明白你需要点开里面的超连,认真研读,按照顺序来.
一.flink官网关于状态的介绍
1. 什么是状态
虽然数据流中的许多操作一次只查看一个单独的事件(例如事件解析器),但有些操作会记住多个事件的信息(例如窗口操作符)。这些操作称为有状态的。这句话读起来有点拗口,简单说一下,所谓的状态就是数据的历史情况,比如你从八点到九点之间吃了二十个包子,然后你在小本本上写上(我在九点到十点吃了十个包子), 等到了第二天,你早上吃了五个包子,于是你打开你的小本本写上(从昨天到今天共吃了10+5=15 个包子),这个小本本上记录的包子的数量就是你的状态信息. 所以说状态是历史信息的叠加, 没看懂的小伙伴建议多吃几个包子体会一下.
下面是状态操作的一些示例:
- 当应用程序搜索某些事件模式时,状态将存储到目前为止遇到的事件序列。
- 当聚合每分钟/小时/天的事件时,状态持有待处理的聚合。
- 在数据点流上训练机器学习模型时,状态保存模型参数的当前版本。
- 当需要管理历史数据时,状态允许有效访问过去发生的事件。
2.State Persistence 状态持久化
flink 使用流重放 (stream replay) 和检查点 (checkpointing)来保证故障容错, checkpoint
为每个stream input 标记一个特殊的point,以及为每个算子operators标记一个状态state .
这句话涵盖了两个方面:
- 一是保存source做检查点的那个瞬间状态,
- 为数据流中每个算子保存一个状态
所以检查点是基于source状态和 算子状态,这些状态存储在heap或者EmbeddedRocksDBStateBackend中,checkoutpoint 要基于状态做快照.
关于状态的存储见Flink state backends
streaming dataflow 流数据流可以从检查点恢复,同时通过恢复操作符的状态并从checkpoint 中的point 重放记录来保持一致性.
容错机制不断地绘制分布式流数据流的快照。对于小状态的流式应用程序,这些快照非常轻量级,可以频繁绘制,对性能没有太大影响。流应用程序的状态存储在可配置的位置,通常在分布式文件系统中。
默认情况下,检查点是禁用的。有关如何启用和配置检查点的详细信息,请参阅检查点。
由于 Flink 的检查点是通过分布式快照实现的,所以我们交替使用快照和检查点这两个词。通常我们也使用术语快照来表示checkpoint或savepoint。
3. Barriers
flink分布式快照一个核心的元素是 stream barriers, 我觉得stream barriers翻译成流栅栏比较好. 这些栅栏被注入到数据流中并且成为data stream 的一部分,随着records流动. barrier 将流动的records分割成一个集合. 每个barrier 都有一个id,另外barrier不会影响数据流,它是异步无感的. (注:来自不同快照的多个屏障可以同时在流中,这意味着各种快照可能同时发生。)
快照n 表示 n之前所有的数据的状态. 这部分是异步快照的知识点,确实不好理解,异步快照 理解barries
**
再说一句:flink state
和检查点是两个概念,states存储了状态,当taskManger执行算子的时候自动保存的,默认存储在内存上,实际开发我们会配置别的存储方式(关于状态的存储见Flink
state
backends),
checkpoint的生成是基于状态的,就是把当前任务涉及到的所有的处理线程涉及到的 state状态以及线程之间的数据缓冲区的数据
统一存储起来建立一个checkpoint,
然后将checkpoint存储在磁盘中,在任务失败的时候,我们可以重启任务加载checkpoint以恢复任务.
**
5. Snapshotting Operator State
当算子operator 包含任何状态state的时候,该state也必将成为快照的一部分.
Operators snapshot their state at the point in time when they have received all snapshot barriers from their input streams, and before emitting the barriers to their output streams. At that point, all updates to the state from records before the barriers have been made, and no updates that depend on records from after the barriers have been applied. Because the state of a snapshot may be large, it is stored in a configurable state backend. By default, this is the JobManager’s memory, but for production use a distributed reliable storage should be configured (such as HDFS). After the state has been stored, the operator acknowledges the checkpoint, emits the snapshot barrier into the output streams, and proceeds.
快照由两部分组成:
- 对于每个并行流数据源,快照启动时流中的偏移量/位置,也就是说source消费的位置.
- 每个算子 的指针,该指针指向state存储的位置.
6. checkpointing
flink 中的每个function 和operator 都是有状态的(see working with state for details),
有状态的function在处理单个元素/事件时存储数据,从而是状态成为一个关键的点. 为了使状态容错,Flink需要对状态进行检查点(也就是说会对状态作快照),Checkpoint允许Flink恢复流中的state和位置,为应用程序提供与无故障执行相同的语义。因为已经处理的流数据不会再次处理, 故障恢复需要之前执行的历史叠加结果也就是状态,所以需要对状态做检查点.
state 做checkpoint ,flink可以从checkpoint恢复state.
7. state 是如何存储的?
state 存储
flink管理的状态是一种分片(shared),是以key/value 存储的,每个关键状态项的工作副本保存在负责该关键的taskmanager 的本地某个地方。状态对于需要它的机器也是本地的,也就是说本地机器存储本地function的状态, 该状态又当前机器的taskmanager管理.
Flink管理的状态存储在状态后端。状态后端有两种实现——一种基于RocksDB,它是一个嵌入式键/值存储,将其工作状态保存在磁盘上;另一种基于堆的状态后端,将其工作状态保存在Java堆的内存中。
- RocksDB
可以存储的状态量大,存储在磁盘上不收机器内存限制,缺点速度慢. 基于增量备份 - java heap
- 速度快,服从jvm GC,也就是可以被回收,缺点耗费内存. 基于全背负
所以说,当使用基于堆的状态保存时,访问和更新涉及读和写堆上的对象。但是对于在EmbeddedRocksDBStateBackend中保存的对象,访问和更新涉及序列化和反序列化,因此磁盘开销要大得多。还需要注意的是,只有EmbeddedRocksDBStateBackend能够进行增量快照,这对于具有大量缓慢变化状态的应用程序来说是一个显著的好处。
这两个状态后端都能够进行异步快照,这意味着它们可以在不妨碍正在进行的流处理的情况下拍摄快照.
8. checkpoint是如何存储的
Flink定期在每个操作符中获取所有状态的持久snapshots ,并将这些snapshots复制到更持久的地方,例如分布式文件系统。在出现故障时,Flink可以恢复应用程序的完整状态,并继续处理,就像没有发生任何错误一样。
存储这些snapshots的位置是通过 job checkpoint storage定义的. checkpoint有两种存储方式,一是分布式文件系统,另一种是JobManager的堆内存中.
-
分布式文件系统存储:
支持大量数据,高可用,推荐生产使用 -
jobManager 的heap存储
一般用于测试情况
9. flink 快照的一些概念
-
Snapshot 一个通用术语,指的是 Flink 作业状态的全局一致图像。快照包括指向每个数据源的指针(例如,文件或 Kafka
分区的偏移量),以及来自每个作业的有状态操作符的状态副本,这些操作符是由于处理了所有事件而导致的来源中的那些位置。 -
Checkpoint – Flink 自动拍摄的快照,目的是能够从故障中恢复。检查点可以是增量的,并针对快速恢复进行了优化。
-
Externalized Checkpoint
外部化检查点——通常检查点不打算由用户操纵。Flink在作业运行时仅保留n个最近的检查点(n可配置),并在作业取消时删除它们。但是您可以将它们配置为保留,在这种情况下您可以手动从它们恢复。 -
Savepoint– 由用户(或 API调用)手动触发的快照,用于某些操作目的,例如有状态的重新部署/升级/重新缩放操作。保存点始终是完整的,并针对操作灵活性进行了优化。
二.我关于状态的理解
官网关于状态的介绍很官方,相信大部分入门的人即便是全部翻译一遍也很难理解。我尝试用通俗的语言来描述我对状态的理解。 首先流数据是源源不断过来的,相信这一点很好理解。比如:ds.map(…)这个很简单的处理, 我们都知道map每次处理一条数据,然后返回处理过的数据。 那么此时如果数据源中的数据是有重复的, 这个需求如果用map来去重的化,你会怎么做?
要知道map每次处理一条数据,但是map并不会保留处理过的数据,换句话说当下一条数据到来的时候其实此刻的map并不知道它曾经处理过什么。
所以常规的思考肯定是无法满足的。请读者看下:flink上下游算子数据传输
,通过阅读flink上下游算子数据传输想必你对状态有了深刻的理解。
2.1flink两种状态
状态怎么用,很多人以为状态只是一个概念,认为flink内部维护的状态,而不是我们来使用的。这种认识大错特错。 正常来说比如ds.map(…)这种算子是没有状态的,但是我们却可以通过自定义实现RichFunction来进行状态式的编程。 正常来说ds.map()输入一条数据,输出一条数据。但是这种默认的行为我们完全可以用状态来更改, 比如我在状态中存储一个int数字表示流经map的数据条数,来一条就加1,直到该数字为三然后统一输出(所谓的输出指的是往map后面的算子传输)。 我举得这个例子就是利用task线程 中的int来记录条数。
所以状态编程可以很强大,强大到超乎你的想象。 而且状态是可以持久化存储的, 可以启用checkpoint, 这样方便故障恢复。
1.keyed state
用于keyBy之后的算子来使用,task为每个key维护一个状态,相同的key的流元素共享状态。
2.operator list state
用于非keyBy之后的算子来使用, task维护一个全局状态,所有流经当前task线程的数据共享状态。
2.两种状态区别
《未完待续》