Flink状态管理

Flink状态管理
State分类:
ManagedState:被Flink管理的State,Flink对他有自己的管理和优化,绝大多数情况适用,
RawState:需要手动管理…自定义Operator的时候需要,
KeyedState:分组操作、OperatorState:有无分组的Operator都可以用;
KeyedState:

/**
 * 需求:使用KeyedState维护历史状态(历史值),获取输入数据的最大值
 * 注意:我们只是为了演示KeyedState,实际中可以直接使用Flink提供好的maxBy,底层已经封装好了状态的维护
 * 所以我们接下来写的代码可以看作是模拟Flink的maxBy的底层
 */
object KeyedStateDemo {
  def main(args: Array[String]): Unit = {
    //1.准备环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    import org.apache.flink.api.scala._
    env.setParallelism(1)
    //2.Source
    val dataDS: DataStream[(Int, Long)] = env.fromElements((2, 1L), (4, 2L), (5, 6L), (5, 4L), (4, 8L),(3,4L))
    val resultDS: DataStream[(Int, Long, Long)] = dataDS.keyBy(_._1).flatMap(new RichFlatMapFunction[(Int, Long), ((Int, Long, Long))] {
      //定义一个KeyState用来存放当前的最大值
      var maxValueState: ValueState[Long] = _
      //创建State
      override def open(parameters: Configuration): Unit = {
        //创建ValueState的描述器(说明一下该State的名称和里面存放的数据类型)
        val maxValueDescriptor: ValueStateDescriptor[Long] = new ValueStateDescriptor[Long]("maxValue", classOf[Long])
        //使用RuntimContext对象根据描述器创建好State并赋值给外部变量
        maxValueState = getRuntimeContext.getState(maxValueDescriptor)
      }
      //在该方法中使用maxValueState用来记录最大值
      override def flatMap(value: (Int, Long), out: Collector[(Int, Long, Long)]): Unit = {
        //获取maxValueState中记录的值
        val maxValue: Long = maxValueState.value()
        val current: Long = value._2
        if (value._2 < maxValue) { 
          out.collect(value._1, value._2, maxValue)
        } else { 
          maxValueState.update(current)
          out.collect(value._1, value._2, current)
        }
      }
    })
    //3.Transformation--使用上面的自定义的keyedState求最大值很麻烦,Flink官方提供的maxBy已经封装好了,可以直接使用,所以开发中直接使用maxBy即可
    val resultDS2: DataStream[(Int, Long)] = dataDS.keyBy(0).maxBy(1)
    //4.sink
    //resultDS.print()
    /*
(2,1,1)
(4,2,2)
(5,6,6)
(5,4,6)
(4,8,8)
(3,4,4)
上面代码求的是不同的key对应的最大值
 */
    resultDS2.print()
    /*
(2,1)
(4,2)
(5,6)
(5,6)
(4,8)
(3,4)
     */

    //5.execute
    env.execute()

  }
}

OperatorState:

object OperatorStateDemo {
  def main(args: Array[String]): Unit = {
    //1.准备环境
    val env: StreamExecutionEnvironment = StreamExecutionEnvironment.getExecutionEnvironment
    import org.apache.flink.api.scala._
    env.setParallelism(1)
    env.enableCheckpointing(1000)
    env.setStateBackend(new FsStateBackend("file:///xxxx"))
    env.getCheckpointConfig.enableExternalizedCheckpoints(ExternalizedCheckpointCleanup.RETAIN_ON_CANCELLATION)
    env.setRestartStrategy(RestartStrategies.fixedDelayRestart(3, 5000))
    //2.Source--使用自定义的数据源模拟KafkaSource需要使用OperatorState来维护offset
    val myKafkaDS: DataStream[String] = env.addSource(new MyKafkaSource())
    //3.sink
    myKafkaDS.print()
    //4.execute
    env.execute()
  }
}
//自定义的数据源模拟KafkaSource需要使用OperatorState来维护offset
//因为是自定义数据所以基础RichParallelSourceFuction
//又因为要使用OperatorState所以需要继承CheckpointedFunction
class MyKafkaSource extends  RichParallelSourceFunction[String] with CheckpointedFunction{
  var flag = true
  //定义一个OperatorState用来存放offset,类型使用OperatorState支持的ListState
  var offsetState:ListState[Long] = _
  //定义一个变量用来存放offset
  var offset:Long = 0L
  //初始化State
  override def initializeState(context: FunctionInitializationContext): Unit = {
    //创建OperatorState状态描述器
    val offsetListStateDescriptor = new ListStateDescriptor[Long]("offsetState",classOf[Long])
    //使用context根据描述器初始化offsetState
    offsetState = context.getOperatorStateStore.getListState(offsetListStateDescriptor)
  }
  //执行State快照(每隔固定的时间将内存中的State数据存储到磁盘的Checkpoint中)
  override def snapshotState(context: FunctionSnapshotContext): Unit = {
    offsetState.clear()//将当前offsetState中记录的数据保存到Checkpoint中并清除
    offsetState.add(offset)//将最新的offset信息存到offsetState中
  }
  //生成数据并递增offset,并将offset存入到offsetState
  override def run(ctx: SourceFunction.SourceContext[String]): Unit = {
    //获取offsetState
    val iter: util.Iterator[Long] = offsetState.get().iterator()
    if (iter.hasNext){//如果offsetState中有值,就取出
      offset = iter.next()
    }
    //生成数据(可以复杂一点包含的信息多一点)并存储offset
    val subtaskIndex: Int = getRuntimeContext.getIndexOfThisSubtask
    while(flag){
      //生成信息较多的数据
      ctx.collect(s"subtask:${subtaskIndex};offset:${offset}")
      //更新offset
      offset+=1
      TimeUnit.SECONDS.sleep(1)
      //模拟一些异常,看程序重启之后是否可以接着上一次的offset消费
      if(offset % 7 == 0){
        println("程序出现异常....")
        throw new RuntimeException("....bug.....")
      }
    }
  }
  override def cancel(): Unit = {
    flag = false
  }
}

Flink-容错-Checkpoint和Flink-State区别
State:程序运行时产生的中间历史结果/记录/状态 ,
State默认保存在JVM内存中,
Checkpoint:标识Flink程序在某一时刻的全局快照,
Checkponit就是State的快照。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值