Flink中的状态
flink流式计算分为有状态的和无状态的
无状态的包括一些简单的算子,比如map fliter ,就是针对当前的数据进行一个逻辑的转换处理就输出了,简单的算子就是输入和输出,这里并没有涉及到状态.
有状态的就没有这么简单了,比如reduce,窗口计算,聚合操作等。最大最小值计算,count的时候,只根据当前的数据没办法得到我们要的结果。必须知道之前统计出来的最大最小值才可以。
状态可以简单的认为就是一个变量,但也不仅仅是一个变量。task在执行的时候就是在slot上执行的一个线程,执行的过程当中,我们用到的所有数据就应该保存在当前线程所独享的一段内存中。所以说当前的状态就是持有的变量而已,可以被当前任务的任意业务逻辑来访问,flink在运行的过程当中会帮我们做状态管理。
自己定义一个变量不就完了?
现在flink是运行在分布式系统,当前的状态在来回做转换操作的时候,可能涉及到序列化和反序列化的过程,特别涉及到比如要做状态一致性的保证,如果发生故障之后,还需要从checkpoint存储的地方拿出来恢复出来。如果只是一个本地变量的话,那当前到底应该按照什么类型去做存储管理呢?无从得知!
flink有自己的整个一套的类型系统,所以当前定义的这些所谓的本地变量,状态,如果想让他有这个容错管理(发生故障能够恢复),那就必须用flink给我们提供的这一套状态管理机制来管理起来。
状态是在哪里存着呢?
在Flink中,状态始终与特定的算子相关联,状态始终在某一个任务中存着的。在使用之前得先注册定义!
一. 状态类型
1.1 算子状态(Operator)
- 其作用范围限定为算子任务,由同一并行任务所处理的所有数据都可以访问到相同的状态
- 状态对于同一子任务而言是共享的
- 算子状态不能由相同或不同算子的另一个子任务访问
算子状态数据结构
- 列表状态(ListState)
将状态表示为一组数据的列表 - 联合列表状态(union list state)
也是将状态表示为数据的列表。与常规列表状态的区别在于,在发生故障时,或者从保存点(SavePoint)启动应用程序时如何恢复 - 广播状态(Broadcast state)
如果一个算子由多项任务,而它的每项任务状态又都相同,这么特殊情况最适合应用广播状态。
特殊的应用场景:可能是一个动态的配置项
1.2键控状态(Keyed State) ----使用较多
- 键控状态是根据输入数据流中定义的键(key)来维护和访问的
- Flink为每个key维护一个状态实例,并将具有相同键的所有数据都分区到同一个算子任务中,这个任务会维护和处理这个key对应的状态
- 当任务处理一条数据时,它会自动将状态的访问范围限定当前数据的key
键控状态数据结构
- 值状态(Value state)
将状态表示为单个的值 - 列表状态(LIst state)
将状态表示为一组数据的列表 - 映射状态(Map state)
将状态表示为一组Key-Value对 - 聚合状态(Reducing state & Aggregating State)
将状态表示为一个用于聚合操作的列表
二. 键控状态的使用
声明一个键控状态
/** keyed state 测试:必须定义在richFunction中,因为需要运行时上下文 */
class MyRichMap extends RichMapFunction[SensorReading,String]{
// 声明一个键控状态
// lazy 定义的惰性变量 会实现延迟加载,即在编译的时候并没有执行
// 惰性变量只能是不可变变量,且只有在调用惰性变量时,才会实例化这个变量
lazy val valueState:ValueState[Double] =getRuntimeContext.getState(new ValueStateDescriptor[Double]("valueState",classOf[Double]))
// 全局定义值状态
var valueState:ValueState[Double] = _
// 定义列表状态
lazy val listState:ListState[Int] = getRuntimeContext.getListState(new ListStateDescriptor[Int]("listState",classOf[Int]))
// 定义mapState 状态
lazy val mapState:MapState[String,Double] = getRuntimeContext.getMapState(new MapStateDescriptor[String,Double]("mapState",classOf[String],classOf[Double]))
// Reducing 状态
lazy val reduceState:ReducingState[SensorReading] = getRuntimeContext.getReducingState(new ReducingStateDescriptor[SensorReading]("reduceState",new MyReduceMapper,classOf[SensorReading]))
override def open(parameters: Configuration): Unit = {
// 定义值状态 只有在open生命周期内才生效
valueState = getRuntimeContext.getState(new ValueStateDescriptor[Double]("valueState",classOf[Double]))
}
override def map(value: SensorReading): String = {
// 值状态的读取
val myV: Double = valueState.value()
// 更新状态
valueState.update(value.temperature)
// 列表状态
listState.add(1)
val list = new util.ArrayList[Int]()
list.add(2)
list.add(4)
listState.addAll(list)
// 更新替换掉列表内所有的数据
listState.update(list)
// 获取整个列表的值,可遍历
listState.get()
//mapState状态操作
mapState.contains("sensor_1") // 是否包含key
mapState.get("sensor_1") // 获取key对应的value
mapState.put("sensor-1",56) // 更新状态
mapState.remove("sensor_1") // 删掉某个值
//
reduceState.get()
reduceState.add(value) // 与之前的状态聚合
value.id
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。