在复杂的流处理场景中都需要记录状态,然后在新流入数据的基础上不断更新状态。
一、什么是状态
流式计算分为无状态计算和有状态计算两种情况。
- 无状态的计算观察每个独立事件,并根据最后一个事件输出结果。
- 有状态的计算会基于多个事件输出结果。
二、状态使用场景
- 去重:对数据流中的重复数据进行去重;
- 检测:如判断一个温度传感器数据流中的温度是否在持续上升;
- 聚合:对一个事件窗口的数据进行聚合分析,比如分析一个小时内水位的情况;
- 更新机器学习模型:在线机器学习场景下,需要根据新流入数据不断更新模型参数;
三、Flink中状态的分类
根据作用域的不同,状态可以分为两类:算子状态(operator state)、键值分区状态(keyed state)。
从具体使用场景来说,绝大多数的算子都可以通过集成Rich函数类或其它提供好的接口类。
Operator State | Keyed State | |
---|---|---|
使用算子类型 | 所有算子:常用于source | 只适用于KeyedStream上的算子 |
状态分配 | 一个算子的子任务对应一个状态 | 一个Key对应一个State:一个算子会处理多个Key,则访问相应的多个State |
创建和访问方式 | 实现CheckpointFunction 接口 |
重写RichFunction,通过里面的RuntimeContext访问 |
横向扩展 | 并发改变时有多重重写分配方式可选:均匀分配和合并后每个得到全量 | 并发改变,State随着Key在实例间迁移 |
支持的数据结构 | ListState、BroadCastState | ValueState、ListState、MapState、ReduceState、AggregationState |
四、状态的使用
1、算子状态使用
算子状态可以用在所有算子上,每个算子子任务或者说每个算子实例共享一个状态,流入这个算子子任务的数据可以访问和更新这个状态。
注意:算子子任务之间的状态不能互相访问。
Operator State的实际应用场景不如Keyed State多,它经常被用在Source或Sink等算子上,用来保存流入数据的偏移量或对输出数据做缓存,以保证Flink应用的Exactly-Once语义。
Flink为算子状态提供三种基本数据结构:
-
列表状态(List state):将状态表示为一组数据的列表。示例: