Flink中的状态
一、Flink中的状态
1)由一个任务维护,并且用来计算某个结果的所有数据,都属于这个任务的状态。
2)可以认为状态就是一个本地变量(一般放在本地内存,本地内存读取修改什么的都比较快),可以被任务的业务逻辑访问。
3)Flink会进行状态管理,包括状态一致性、故障处理以及高效存储和访问,以便开发人员可以专注于应用程序的逻辑。
像map、filter、flatMap这些算子,来一个输出一个,不依赖于其它的数据,也不依赖于之前的结果,所以它们是无状态的算子。
像window、reduce、聚合等一些操作,需要依赖于之前计算的结果,所以这些算子都属于有状态的算子。
在Flink中,状态始终与特定算子相关联(其实,在map、filter里面可以定义状态),跟特定的任务绑定在一起的,后面发生的任务不能访问到前面任务的状态,因为后面任务可能跟前面任务不在一个taskManager或者slot,如果要访问状态,需要做网络传输,而状态是在内存中的,不可能做网络传输。
为了使运行时的Flink了解算子的状态,算子需要预先注册其状态
总的来说,有两种类型的状态:
算子状态(Operator State):算子状态的作用范围限定为算子任务
键控状态(Keyed State):根据输入数据流中定义的键(key)来维护和访问
1、算子状态
上图中两个Task1属于一个算子的两个并行子任务,它们不在一个slot上,甚至不在一个TaskManager上,所以不能访问别人的状态。
1)算子状态的作用范围限定为算子任务,由同一并行任务(上图上面的一个Task1属于一个并行子任务,下面那个也是一个并行子任务,所以有两个并行子任务)所处理的所有数据都可以访问到相同的状态。
2)状态对于同一子任务而言是共享的(一个Task1里所有数据都共享这个状态)。
3)算子状态不能由相同或不同算子的另一个子任务访问(即使上图中的两个Task1是一个算子的两个子任务,也不能互相访问)。
4)只要在同一个分区,不管key相不相同,访问的都是一个状态。
1.1 算子状态数据结构
1)列表状态(List state)
将列表表示为一组数据的列表(在故障恢复之后,可能会发生并行度的调整,如果要进行聚合还好说,如果要拆分就不容易去拆分)
2)联合列表状态(Union list state)
也将状态表示为数据的列表。它与常规列表状态的区别在于,在发生故障时,或者从保存点(savepoint)启动应用程序时如何恢复。
例如有两个并行子任务,每个并行子任务有三个状态,经过故障恢复后要并行度变为3,如果是列表状态,会把第一个子任务的前两个状态分给分区后的1,会把第二个子任务的前两个状态分给分区后的2,会把剩下的状态分给分区后的3;如果是联合列表状态,会把这六个状态给下游全部分发一份,让它们自己挑选状态。
3)广播状态(Broadcast state)
如果一个算子有多项任务,而它的每项任务状态又都相同,那么这种特殊情况最适合应用广播状态。
1.2 算子状态案例
需求:定义一个有状态的map操作,统计当前分区数据个数
代码如下:
下面代码可以实现一个有状态的map操作,可以统计当前分区内数据个数,但是如果不做特殊说明,容错的时候不会进行相应的处理,本地变量在内存中,没办法进行恢复,只能重新从0开始count。
//定义一个有状态的map操作,统计当前分区的数据个数
mapResult.map(new MapFunction<SensorReading, Integer>() {
//定义一个本地变量作为算子状态
private Integer count=0;
@Override
public Integer map(SensorReading sensorReading) throws Exception {
count++;
return count;
}
})
进行了容错配置的代码(还需要额外实现ListCheckpointed接口):
mapResult.map(new MyCountMapper());
public static class MyCountMapper implements MapFunction<SensorReading,Integer>, ListCheckpointed<Integer>{
//定义一个本地变量作为算子状态
private Integer count=0;
@Override
public Integer map(SensorReading sensorReading) throws Exception {
count++;
return count;
}
//Checkpoint触发时会调用这个方法,我们要实现具体的snapshot逻辑,比如将哪些本地状态持久化
//对状态做快照,返回一个Integer的List
@Override
public List<Integer> snapshotState(long l, long l1) throws Exception {
return Collections.singletonList