第1章 有状态的流计算
State(状态)是流式应用中普遍存在的一种对象,在流计算整个过程中,算子会不断的对状态进行读取和更新。在Flink当中既有内置的状态,也支持用户自定义状态。算子计算结果保存在state当中,下一笔数据到来时采用上一次计算结果和本次数据一起进行计算。而Flink流计算的状态数据是以state形式存在state backends中。
在Flink当中,提及State与Checkpoint和Savepoint息息相关,它们产生的快照的数据就来源于各个算子产生的State。(Checkpoint和Savepoint在后续文章中详细说明)。
常见的State使用有:
- Window窗口计算;
- 计算时中间结果的实时读写;
- 数据源读取进度,对数据源source记录消费位置;
- 机器学习模型之类的特定应用状态;
注意:流计算长时间运行,使用时一定要考虑state的清理。
在Flink里状态可以分为两类:operator state(算子状态)和keyed state(键值分区状态),下面我们详细的介绍着两种state。
第2章 Flink中的State
2.1 Operator state(算子状态)
Operator state的作用域是算子任务,所有在同一个并行任务之内的记录都能访问到相同的state。注意Operator state不能通过其他任务访问,无论任务是否来自相同算子。
Flink为operator state提供三种语义:
- list state:列表状态,state表示为一个列表
- union list state:联合列表状态,state表示为一个列表,但此状态恢复的方式与list state有所不同
- broadcast state:广播状态,顾名思义,将state广播给每个算子任务,专门为需要保证算子的每个任务状态都相同的业务场景而设计。
2.2 Keyed state(键值分区状态)
Keyed state是按照算子输入数据所定义的键值来进行维护或访问。Flink为每个key都维护了一个状态实例,该实例总是位于处理对应key值记录的算子任务上。在算子处理数据时,Flink会自动把Keyed state访问范围限制为当前记录的Key值。也就是说,所有key值相同的记录都能访问到一样的state。
第3章 State backend(状态后端)
在Flink中,每个并行任务都会把state维护在本地,而state的存储、访问、维护,就是由state backend来完成。state backend主要负责:本地状态的管理、将本地state以checkpoint的方式写入远端存储。
下面我们介绍一下目前Flink当中三种state backend。
3.1 Memory
MemoryStateBackend的特点:
- 基于JVM Heap内存,注意OOM风险
- 持久化时State传输到远端Jobmanager,并存储在JobManager当中,而JobManager同样时存储在内存当中。
- Memory内,在传输到远端DFS的时候需要经过一个序列化和反序列化的过程。
存储方式:
- 本地存储:TaskManager的内存中;
- 远端存储:JobManager的内存中。
适用场景:
- 开发测试使用,或者状态小的流计算场景。
3.2 FS
FsStateBackend的特点:
- 基于JVM Heap内存,注意OOM风险;
- 持久化时State存储到文件系统当中,文件目录和文件名上传到远端的JobManager,State不上传到JobManager;
- 本地文件的状态后端,支持全量CP,不支持增量CP。
存储方式:
- 本地存储:TM的内存中;
- 远端存储:本地文件系统或分布式文件系统(如:HDFS)。
适用场景:
- 适合状态较大的高可用场景。
3.3 RocksDB
RocksDBStateBackend的特点:
- 基于RocksDB,操作本地文件系统。
- State可以维护Disk里,每次读取的时候需要经过序列化和反序列化的一个过程,传输到远端DFS的时候就不要在进行序列化和反序列化的操作。
- 状态不上传到JobManager,支持增量持久化,增量CP。
- 如果要在Flink里使用RocksDB作为State backend,需要将相关jar包引入,RocksDB在Flink中使用属于插件类型应用。
存储方式:
- 本地存储:RocksDB;
- 远端存储:分布式文件系统(如HDFS)。
使用场景:
- 适合大状态高可用场景,有增量CP的性能优势。