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
  }
}

三.状态后端(State Backends)


踏月V
1 声望0 粉丝

引用和评论

0 条评论