Flink如何实现有状态的计算

Flink如何实现有状态的计算,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。

流式计算分为无状态和有状态两种情况。无状态计算观察每个独立的事件,风暴就是无状态的计算框架,每一条消息来了以后和前后都没有关系,一条是一条。比如我们接收电力系统传感器的数据,当电压超过240 v就报的警,这就是无状态的数据。但是如果我们需要同时判断多个电压,比如三相电路,我们判断三相电都高于某个值,那么就需要将状态保存,计算,因为这三条记录是分别发送过来的。

 Flink如何实现有状态的计算

风暴需要自己实现有状态的计算,比如借助于自定义的内存变量或者复述等系统,保证低延迟的情况下自己去判断实现有状态的计算,但是Flink就不需要这样,而且作为新一代的流处理系统,Flink非常重视。

一致性

其实就是消息传递的正确性。在流处理中,一致性分为3个级别。

<李>

至多一次:最多一次,可能会丢失。

<李>

“至少一次”:最少一次,可能会重复,而计算的时候可能就会多次运算影响结果。

<李>

只有一次:恰好保证一次,这样得到的结果是最准确的。

最先保证仅一次的系统(风暴三叉戟和火花流),但是在性能和表现力这两个方面付出了很大的代价。为了保证仅一次,这些系统无法单独地对每条记录运用应用逻辑,而是同时处理多条(一批)记录,保证对每一批的处理要么全部成功,要么全部失败。这就导致在得到结果前,必须等待一批记录处理结束,因此,用户经常不得不使用两个流处理框架(一个用来保证仅一次,另一个用来对每个元素做低延迟处理),结果使基础设施更加复杂。

但是,Flink解决了这种问题。

检查点机制

检查点是Flink最有价值的创新之一,因为它使Flink可以保证仅一次,并且不需要牺牲性能。

Flink检查点的核心作用是确保状态正确,即使遇到程序中断,也要正确。记住这一基本点之后,我们用一个例子来看检查点是如何运行的.Flink为用户提供了用来定义状态的工具,例如,以下这个Scala程序按照输入记录的第一个字段(一个字符串)进行分组并维护第二个字段的计数状态。

 <代码> val流:DataStream数据[(String、Int)]=?br/> 
val计数:DataStream数据[(String、Int)]=
。keyBy(记录=比;record._1)
。:mapWithState (((String、Int),数:选项(Int))=比;,,
,计算匹配{
,,,一些(c)=比;((。_1,c + in._2),一些(c + in._2))
,,,情况没有=比;((。_1,in._2),一些(in._2))
})

该程序有两个算子:keyBy算子用来将记录按照第一个元素(一个字符串)进行分组,根据该键将数据进行重新分区,然后将记录再发送给下一个算子:有状态的地图算子(mapWithState) . map算子在接收到每个元素后,将输入记录的第二个字段的数据加到现有总数中,再将更新过的元素发射出去。

 Flink如何实现有状态的计算

输入流中的6条记录被检查点屏障(检查点屏障)隔开,所有的地图算子状态均为0(计数还未开始)。所有键为的记录将被顶层的地图算子处理,所有主要为b的记录将被中间层的地图算子处理,所有关键为c的记录则将被底层的地图算子处理。

如果输入流来自消息传输系统卡夫卡,这个相互隔离的位置就是偏移量。

 Flink如何实现有状态的计算

检查点屏障像普通记录一样在算子之间流动。当地图算子处理完前3条记录并收到检查点屏障时,它们会将状态以异步的方式写入稳定存储。

 Flink如何实现有状态的计算

当没有出现故障时,Flink检查点的开销极小,检查点操作的速度由稳定存储的可用带宽决定。

如果检查点操作失败,Flink会丢弃该检查点并继续正常执行,因为之后的某一个检查点可能会成功。

 Flink如何实现有状态的计算

在这种情况下,Flink会重新拓扑(可能会获取新的执行资源),将输入流倒回到上一个检查点,然后恢复状态值并从该处开始继续计算。

Flink如何实现有状态的计算