
先简单介绍一下什么是状态?
状态包括计算中所有的计算结果,可以认为是一个外部存储的本地变量,当然要结合不同的模式。
状态管理包括状态一致性、故障处理、高级存储和访问
有两种类型的状态
1、算子状态
在同一个任务中的算子状态,作用范围也只有这个任务,并行的所有数据都能访问到相同的状态,但是不能跨slot,在同一个任务是共享的,不能由另一个任务访问
数据结构包括:列表状态(list state)、联合列表状态(union list state)、广播状态(broadcast state)
2、键控状态
顾名思义,跟键值对类似,为不同的key维护一个状态示例,相同键的所有数据都在同一个分区上,在处理一条数据的时候根据key自动能判断出当前的范围
数据结构包括:值状态(value state)、列表状态(list state)、映射状态(map state)、聚合状态(reducing state & aggregating state)
接下来我们看一下状态后端 state backends
以上我们讲了状态,那么状态后端就是管理这个状态的一个组件,管理状态的存储、访问、维护等,同时还将检查点(checkpoint)状态写入存储,存储方式如下三种:
MemoryStateBackend
内存级状态后端,将所有状态的对象丢到TaskManager的JVM堆上,而checkpoint存在JobManager的内存中
优点:快、低延迟
缺点:可控数据量的任务比较适合,但当下大部分场景数据量都不可预估,无法估量一个内存大小能稳定运行,因此这个模式我们大多用在测试或者调试上
FsStateBackend
将checkpoint存在远端的持久化文件系统上(如minio、hdfs等分布式文件系统),而本地状态都存在TaskManager上的JVM堆上
优点:保证容错的同时有着较快的访问速度
缺点:跟MemoryStateBackend相同的问题,虽然state是可以设置过期的,但无法预估TaskManager能正常运行
RocksDBStateBackend
所有状态序列化都存在本地的RocksDB中,根据策略存储到远端的持久化文件系统上
优点:满足绝大多数场景,舍弃了一部分快速访问的性能,换取能处理更大数据量级的能力,大部分生产环境建议使用这种模式
缺点:相比另外两种模式,读写和访问性能较低
状态后端的设置根据不同的版本有着不同的设置,主要区分在1.11版本前后
1.11版本之前:
state.backend:('jobmanager', 'filesystem', 'rocksdb')
1.11版本之后:
state.backend:('hashmap', 'rocksdb')
state.checkpoint-storage:(jobmanager | filesystem)
其他参数配合来使用
下面我们介绍一下什么是checkpoint,这个概念在很多分布式系统中都有,而在flink中根据对应策略,比如某个时间点,把所有的状态进行一份快照备份,同时输出到对应的存储系统中(内存|外部分布式文件存储系统)
通过使用checkpoint来保证exactly-once语义,后面我们专门开个帖子来说
总结:
作为flink的四大件之一,状态是一个非常重要的组成部分,除了完成业务的状态使用外,实现checkpoint(自动)和savepoint(手动)来确保任务的容错,并且能在错误的情况下断点恢复,