Flink状态管理
Flink状态管理
Flink中的状态
由一个任务维护,并且用来计算某个结果的所有数据,都属于这个任务的状态
可以认为状态就是一个本地变量,可以被任务的业务逻辑访问
Flink
会进行状态管理,包括状态一致性、故障处理以及高效存储和访问,以便开发人员可以专注于应用程序的逻辑
再Flink
中,状态始终与特定算子相关联
为了使运行时的Flink
了解算子的状态,算子需要预先注册其状态
有状态的算子和应用程序
Flink
内置的很多算子,数据源 source
,数据存储 sink
都是有状态的,流中的数 据都是 buffer records
,会保存一定的元素或者元数据。例如: ProcessWindowFunction
会缓存输入流的数据,ProcessFunction
会保存设置的定时器信息等等。
在 Flink
中,状态始终与特定算子相关联。总的来说,有两种类型的状态:
-
算子状态(operator state)
-
键控状态(keyed state)
算子状态
算子状态的作用范围限定为算子任务。这意味着由同一并行任务所处理的所有数据都可以访问到相同的状态状态对于同一任务而言是共享的。算子状态不能由 相同或不同算子的另一个任务访问。
Flink
为算子状态提供三种基本数据结构:
-
列表状态(
List state
) 将状态表示为一组数据的列表。 -
联合列表状态(
Union list state
) 也将状态表示为数据的列表。它与常规列表状态的区别在于,在发生故障时,或者从保存点(savepoint
)启动应用程序时如何恢复。 -
广播状态(
Broadcast state
) 如果一个算子有多项任务,而它的每项任务状态又都相同,那么这种特殊情况最适合应用广播状态。
键控状态(keyed state)
键控状态是根据输入数据流中定义的键(key
)来维护和访问的。Flink
为每个键值维护 一个状态实例,并将具有相同键的所有数据,都分区到同一个算子任务中,这个任务会维护 和处理这个 key
对应的状态。当任务处理一条数据时,它会自动将状态的访问范围限定为当 前数据的 key
。因此,具有相同 key
的所有数据都会访问相同的状态。Keyed State
很类似于 一个分布式的 key-value map
数据结构,只能用于KeyedStream
(keyBy
算子处理之后)
Flink
的 Keyed State
支持以下数据类型:
-
ValueState[T]
保存单个的值,值的类型为 T。-
get
操作:ValueState.value()
-
set
操作:ValueState.update(value: T)
-
-
ListState[T]
保存一个列表,列表里的元素的数据类型为 T。基本操作如下:-
ListState.add(value: T)
-
ListState.addAll(values: java.util.List[T])
-
ListState.get()
返回Iterable[T]
-
**
ListState.update(values: java.util.List[T])
**
-
-
MapState[K, V]
保存Key-Value
对。-
MapState.get(key: K)
-
MapState.put(key: K, value: V)
-
MapState.contains(key: K)
-
MapState.remove(key: K)
-
-
ReducingState[T]
-
AggregatingState[I, O]
键控状态的代码实现
状态的实现需要定义在富函数中,因为状态需要联系上下文才行
通过 RuntimeContext
注册 StateDescriptor
。StateDescriptor
以状态state
的名字 和存储的数据类型为参数。 在 open()
方法中创建state
变量。注意复习之前的 RichFunction
相关知识。
例如创建一个valueState
状态
class MyRichMapper extends RichMapFunction[SensorReading, String] {
var valueState: ValueState[Double] = _
override def open(parameters: _root_.org.apache.flink.configuration.Configuration): Unit = {
valueState = getRuntimeContext.getState(
new ValueStateDescriptor[Double]("valueState", classOf[Double]))
}
override def map(in: _root_.Source.SensorReading): _root_.scala.Predef.String = {
//状态读取数据
val myValueState = valueState.value()
//状态更改值
valueState.update(in.temperature)
in.id
}
}
其实不一定非要再open
方法中定义,也可以使用lazy
来定义,入下面来定义一个listState