Flink中的状态管理器
flink提供了三种状态管理器分别是:
- 基于内存的MemoryStateBackend
- 基于文件系统的FsStateBackend
- 基于RockDB的RocksDBStateBackend
1. MemoryStateBackend
MemoryStateBackend将状态数据全部存储于JVM堆内存中。MemoryStateBackend是Flink的默认状态管理器。状态数据包括用户使用的DataStream API创建的Key/Value State、窗口中缓存的状态数据和触发器等数据。基于内存的状态管理器速度快且高效,但具有内存容量有限等限制。一旦存储的状态数据过多就会导致系统内存溢出等问题。内存数据的易失性,如果机器出问题,整个主机内存中的状态数据就会丢失,进而无法恢复任务中的状态数据。因此MemoryStateBackend存在数据安全性问题,不建议用户在生产环境中使用。
MemoryStateBackend可以通过配置来使用异步快照(Asynchronous Snapshots)。通过异步快照可以避免阻塞管道(Blocking Pipelines),目前是默认开启,当然也可以通过MemoryStateBackend的构造函数配置进行关闭:
new MemoryStateBackend(MAX_MEM_STATE_SIZE, false);
其中MAX_MEM_STATE_SIZE指定每个状态值最大的内存使用大小。
MemoryStateBackend特点
- 聚合状态(Aggregate State )必须放入JobManager的内存。聚合类算子的状态存储在JobManager内存中,因此对聚合类算子比较多的应用汇对JobManager的内存造成一定压力,继而对整个集群性能会有影响。
- 状态的大小不能超过akka的framesize大小。尽管创建MemoryStateBackend时可指定状态初始化内存大小,但是由于数据在JobManager和TaskManage之间传输受限于Akka框架通信的akka.framesize大小,所以状态数据大小不能超过akka.framesize(默认10485760bit)。
- 不合适状态数据非常大的情况。由于JVM内存容量受限于主机内存,不管JobManager还是TaskManager,器维护状态数据都受到内存限制。
-
MemoryStateBackend的适用场景:测试环境、本地调试和验证,flink任务状态数据量较小的场景或者只涉及非状态算子计算的场景。不建议生产环境中使用。
2 FsStateBackend
FsStateBackend是基于文件系统的状态管理器,文件系统可以说HDFS等分布式文件系统,也可以是本地文件系统。FsStateBackend将动态数据保存在taskmanger的内存中,通过checkpoint机制,将状态快照写入配置好的文件系统或目录中。最小元数据保存jobManager的内存中,另外FsStateBackend通过配置一个fileStateThreshold阈值,小于该值时state存储到metadata中而非文件中。
FsStateBackend默认通过配置来使用异步快照(asynchronous snapshots)避免阻塞管道(blocking pipelines),当然也可以通过FsStateBackend的构造函数配置进行关闭:
new FsStateBackend(path, false);
其中,path是文件路径,若为本地路径,格式为:file:///data/flink/checkpoints,若是HDFS路径,格式为:hdfs://namenode:40010/flink/checkpoints。FsStateBackend第二个参数Boolean类型,指定是否以同步的方式进行状态数据记录。默认false,采用异步的方式将状态数据同步到文件系统中,异步方式能够尽可能避免在Checkpoint的过程中影响流式计算任务。如果用同步方式进行状态数据额检查点数据,设为true。
FsStateBackend特点
- FsStateBackend比较稳定。
- 借助HDFS 等分布式文件系统中具有三个副本备份的策略,能最大程度保证状态数据的安全性,不会因外部故障导致任务无法恢复等问题。
- FsStateBackend适用场景1)大状态,2)长窗口如时间范围非常长的窗口计算,3)key/value状态数据非常大 的任务,4)全高可用配置
3.RocksDBStateBackend
RocksDBStateBackend是Flink内置的第三方状态管理器,如使用单任务配置用需先加入依赖:
<dependency>
<groupId>org.apache.flink</groupId>
<artifactId>flink-statebackend-rocksdb_${scala.binary.version}</artifactId>
<version>1.8.0</version>
</dependency>
RocksDBStateBackend采用异步的方式进行状态数据的snapShot,先将工作状态数据保存在RocksDB数据库(位置在taskManagerd的数据目录)。然后,通过checkpoint, 整个RocksDB数据库被复制到配置的文件系统或目录中。这样RockDB仅会存储正在进行计算的热塑局,对于长时间才更新的数据则写入到文件系统。而体量比较小的元数据状态则直接保存jobManager的内存中。RocksDBStateBackend可以通过enableIncrementalCheckpointing参数配置是否进行增量Checkpoint(而MemoryStateBackend 和 FsStateBackend不能)。
RocksDBStateBackend特点
- RocksDBStateBackend仅支持异步快照。与FsStateBackend 不同的是,RocksDBStateBackend仅支持异步快照(asynchronous snapshots)。
- RocksDBStateBackend每次合并的状态数据不能超过
字节。RocksDB通过JNI的方式进行数据交互,JNI构建在byte[]数据结构回去,因此每次传输的最大数据量为
字节,所以RocksDBStateBackend每次合并的状态数据不能超过
字节,否则会导致状态数据无法同步。
- RocksDBStateBackend适用场景:大状态、长窗口、大key/value状态的的任务、全高可用配置
- Flink已经提供了基于RocksDBStateBackend实现的增量Checkpoint功能,极大提高了状态数据同步到介质的效率和性能。
- 由于RocksDBStateBackend将工作状态存储在taskManger的本地文件系统,状态数量仅仅受限于本地磁盘容量限制,对比于FsStateBackend保存工作状态在内存中,RocksDBStateBackend能避免flink任务持续运行可能导致的状态数量暴增而内存不足的情况,因此适合在生产环境使用。
参考
[1] flink状态后端配置-设置State Backend(https://www.jianshu.com/p/ac0fff780d40)
[2] 聊聊flink的MemoryStateBackend(https://www.jianshu.com/p/91fb5169af71)
[3] Flink 三种状态存储方式 MemoryStateBackend、FsStateBackend、RocksDBStateBackend(https://blog.csdn.net/u010002184/article/details/106974208/)