前提知识:有状态和无状态
无状态计算会观察每个独立的事件,并且会在最后一个时间出结果,例如一些报警和监控,一直观察每个事件,当触发警报的事件来临就会触发警告。
有状态的计算就会基于多个事件来输出结果,比如说计算过去一个小时的平均温度等等。
状态计算就可以将接入的事件进行存储,然后等待符合规则的事件触发:
- 用户想按照分钟,小时、天进行聚合计算,求取当前的最大值、均值等聚会指标,这就需要利用状态来维护当前计算过程中产生的结果,例如事件的总数,总和以及最大,最小值。
- 用户想在Strem上实现机器学习的模型训练,状态计算可以帮助用户维护当前版本模型使用的参数
- 用户想使用历史的数据进行计算,状态计算可以帮助用户对数据进行缓存,使用户可以直接从状态中获取相应的历史数据。
用白话来说,有状态就是能拿到历史的数据,历史数据包括了历史消息的计算结果,计算结果也包含历史窗口计算的结果,因此不能片面认为支持窗口就是有状态的。
Flink状态之状态存储 state backends
流计算中可能有各种方式来保存状态:
- 窗口操作
- 使用 了KV操作的函数
- 继承了CheckpointedFunction的函数
当开始做checkpointing的时候,状态会被持久化到checkpoints里来规避数据丢失和状态恢复。选择的状态存储策略不同,会导致状态持久化如何和checkpoints交互。
Flink提供了三种持久化策略:
- MemoryStateBackend:将数据保存在java的堆里,kv状态或者window operator用hash table来保存values,triggers等等。适合于:
- 本地开发和调试。
- 状态比较少的作业
- FsStateBackend:保持数据在TM的内存中,当做checkpointing的时候,会将状态快照写入文件,保存在文件系统或本地目录。少量的元数据会保存在JM的内存中。适合于:
- 状态比较大,窗口比较长,大的KV状态
- 需要做HA的场景
- RocksDBStateBackend:保存数据在一个叫做RocksDB的数据库中,这个数据库保存在TM的数据目录中。当做checkpointing时,整个数据库会被写入文件系统和目录。少量的元信息会保存在JM的内存中。适合于:
- 非常大的状态,长窗口,大的KV状态
- 需要HA的场景
可参考博客,链接