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的快照。