状态编程和容错机制(一)
我们知道Flink是一个流式计算引擎,也就是数据上来一条处理一条。那Flink是怎样完成窗口计算的呢?比如:我要取5秒钟之内传感器温度最大值。如果只是来一条数据处理一条这显然无法完成上述需求。如果能够将当前的最大值保存起来,下一条数据来到后与保存的最大值作比较,更新最大值并保存再与下一条数据比较,这样就可以完成上述需求了。这个保存起来的最大值就是状态。
容错机制是所有的分布式程序都需要有的一种处理错误的机制。比如:任务跑着跑着突然…服务器冗机了,当服务器启动之后怎样才能让任务接着冗机之前开始跑呢?这就需要一套容错机制来处理。
下面我们对状态编程和容错机制展开说一说
状态编程
下图解释了无状态编程和有状态编程的区别
从上图可以看出无状态编程时数据操作完直接输出。而有状态编程数据在操作过程中会与现有状态进行交互这种交互可以是累加或者比较等等然后将操作后的数据输出同时更新状态。显然无状态编程不适用于流式处理框架。
有状态的算子和应用程序
Flink中的状态可以分为三类,分别是:
- 算子状态(operate state)
- 广播状态(Broadcast State)
- 键控状态(key state)
算子状态
算子状态是作用在算子任务级别的状态。在同一任务中状态是共享的。相对的如果是相同算子或者不同算子的一个任务是无法访问另一个任务的状态的。
比较典型的算子状态的例子:Kafka的Source和Sink,Kafka消费者的每一个并行实例会将主题分区和偏移量信息保存为算子状态。
如果数据已经进行key by操作,那么就不推荐使用算子状态了。
算子状态有两种基本的数据结构:
-
列表状态(List state)
Even-split redistribution:事件分割后再分配。每一个算子都会产生一个状态元素列表,一个完整的状态信息是这些列表的合集。当服务重启或重新分发时,这个状态集合会被分割成与并行度相同数量的子集,而这些子集会被分发配到不同的并行算子中。
-
联合列表状态(union list state)
Union redistribution:联合在分配。每一个算子都会产生一个状态元素列表,一个完整的状态信息是这些列表的合集。当服务重启或重新分发时,每个算子都会获取完整的状态信息。因此状态数据量过大时不要使用联合列表状态。
广播状态
广播状态是特殊的算子状态。广播状态是可以在相同算子的不同任务中被调用的。并且:
- 数据格式是Map格式的
- 只适用于一条广播流和一条非广播流作为输入的特定算子
- 一个算子可以有多个不同名字的广播流
键控状态
键控状态是根据输入数据流中定义的键(key)来维护和访问的。Flink会为每一个键值维护一个状态实例,并将具有相同键的所有数据,都分区到同一个算子任务中,这个任务会维护和处理这个key对应的状态。
只有在keyBy算子之后才能使用键控状态。
键控状态包括以下数据类型:
- ValueState:
- get()
- update(T)
- ListState:
- add(T)
- addAll(List)
- get()
- update(List)
- MapState<key,value>:
- get()
- put(key,value)
- contains(key)
- remove(key)
- ReducingState:
- AggregatingState<IN, OUT>&