超越Storm,SparkStreaming——Flink如何实现有状态的计算

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

Storm需要自己实现有状态的计算,比如借助于自定义的内存变量或者redis等系统,保证低延迟的情况下自己去判断实现有状态的计算,但是Flink就不需要这样,而且作为新一代的流处理系统,Flink非常重视。
一致性
其实就是消息传递的正确性。在流处理中,一致性分为 3 个级别。
at-most-once:最多一次,可能会丢失。
at-least-once:最少一次,可能会重复,而计算的时候可能就会多次运算影响结果。
exactly-once:恰好保证一次,这样得到的结果是最准确的。
最先保证 exactly-once 的系统(Storm Trident 和 Spark Streaming),但是在性能和表现力这两个方面付出了很大的代价。为了保证 exactly-once,这些系统无法单独地对每条记录运用应用逻辑,而是同时处理多条(一批)记录,保证对每一批的处理要么全部成功,要么全部失败。这就导致在得到结果前, 必须等待一批记录处理结束。因此,用户经常不得不使用两个流处理框架 (一个用来保证 exactly-once,另一个用来对每个元素做低延迟处理),结果使基础设施更加复杂。
但是,Flink解决了这种问题。
检查点机制
检查点是 Flink 最有价值的创新之一,因为它使 Flink 可以保 证 exactly-once,并且不需要牺牲性能。
Flink 检查点的核心作用是确保状态正确,即使遇到程序中断,也要正确。 记住这一基本点之后,我们用一个例子来看检查点是如何运行的。Flink 为 用户提供了用来定义状态的工具。例如,以下这个 Scala 程序按照输入记录 的第一个字段(一个字符串)进行分组并维护第二个字段的计数状态。
val stream: DataStream[(String, Int)] = ...
val counts: DataStream[(String, Int)] = stream
.keyBy(record => record._1)
.mapWithState((in: (String, Int), count: Option[Int]) =>
count match {
case Some(c) => ( (in._1, c + in._2), Some(c + in._2) )
case None => ( (in._1, in._2), Some(in._2) )
})
该程序有两个算子:keyBy 算子用来将记录按照第一个元素(一个字符串) 进行分组,根据该 key 将数据进行重新分区,然后将记录再发送给下一个算子:有状态的 map 算子(mapWithState)。 map 算子在接收到每个元素后, 将输入记录的第二个字段的数据加到现有总数中,再将更新过的元素发射出去。

输入流中的 6 条记录被检查点屏障 (checkpoint barrier)隔开,所有的 map 算子状态均为0(计数还未开始)。 所有 key 为 a 的记录将被顶层的 map 算子处理,所有 key 为 b 的记录将被中间层的 map 算子处理,所有 key 为 c 的记录则将被底层的 map 算子处理。
如果输入流来自消息传输系统Kafka,这个相互隔离的位置就是偏移量。

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

当没有出现故障时,Flink 检查点的开销极小,检查点操作的速度由稳定存储的可用带宽决定。
如果检查点操作失败,Flink 会丢弃该检查点并继续正常执行,因为之后的 某一个检查点可能会成功。

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

Flink 将输入流倒回到上一个检查点屏障的位置,同时恢复 map 算子的状态值。 然后,Flink 从此处开始重新处理。这样做保证了在记录被处理之后,map 算子的状 态值与没有发生故障时的一致.
Flink 检查点算法的正式名称是异步屏障快照(asynchronous barrier snapshotting)。
保存点
状态版本控制
检查点由 Flink 自动生成,用来在故障发生时重新处理记录,从而修正状 态。Flink 用户还可以通过另一个特性有意识地管理状态版本,这个特性叫作保存点(savepoint)。
保存点与检查点的工作方式完全相同,只不过它由用户通过 Flink 命令行工 具或者 Web 控制台手动触发,而不由 Flink 自动触发,用户可以从保存点重启作业,而不用从头开始。对保存点的另一种理解是,它在明确的时间点保存应用程序状态的版本。

在图中,v.0 是某应用程序的一个正在运行的版本。我们分别在 t1 时刻和 t2 时刻触发了保存点。因此,可以在任何时候返回到这两个时间点,并且重 启程序。更重要的是,可以从保存点启动被修改过的程序版本。举例来说, 可以修改应用程序的代码(假设称新版本为 v.1),然后从t1 时刻开始运行 改动过的代码。

使用保存点更新Flink 应用程序的版本。新版本可以从旧版本生成的一个 保存点处开始执行.
端到端的一致性

在该应用程序架构中,有状态的Flink 应用程序消费来自消息队列的数据, 然后将数据写入输出系统,以供查询。
输入数据来自Kafka,在将状态内容传送到输出存储系统的过程中,如何保证 exactly-once 呢?这 叫作端到端的一致性。本质上有两种实现方法,用哪一种方法则取决于输 出存储系统的类型,以及应用程序的需求。
(1) 第一种方法是在 sink 环节缓冲所有输出,并在 sink 收到检查点记录时, 将输出“原子提交”到存储系统。这种方法保证输出存储系统中只存在 有一致性保障的结果,并且不会出现重复的数据。从本质上说,输出存 储系统会参与 Flink 的检查点操作。要做到这一点,输出存储系统需要 具备“原子提交”的能力。
(2) 第二种方法是急切地将数据写入输出存储系统,同时牢记这些数据可能 是“脏”的,而且需要在发生故障时重新处理。如果发生故障,就需要将 输出、输入和 Flink 作业全部回滚,从而将“脏”数据覆盖,并将已经写 入输出的“脏”数据删除。注意,在很多情况下,其实并没有发生删除 操作。例如,如果新记录只是覆盖旧纪录(而不是添加到输出中),那么 “脏”数据只在检查点之间短暂存在,并且最终会被修正过的新数据覆盖。
根据输出存储系统的类型,Flink 及与之对应的连接器可以一起保证端到端 的一致性,并且支持多种隔离级别。
更多Flink相关文章:
更多实时计算,Flink,Kafka等相关技术博文,欢迎关注实时流式计算:

超越Storm,SparkStreaming——Flink如何实现有状态的计算的更多相关文章
- Flink,Storm,SparkStreaming性能对比
Yahoo 的 Storm 团队曾发表了一篇博客文章 ,并在其中展示了 Storm.Flink 和 Spark Streaming 的性能测试结果.该测试对于业界而言极 具价值,因为它是流处理领域的第 ...
- Spark技术的总结 以及同storm,Flink技术的对比
spark总结 1.Spark的特点: 高可伸缩性 高容错 基于内存计算 支持多种语言:java,scala,python,R 高质量的算法,比MapReduce快100倍 多种调度引擎:可以运行于Y ...
- Storm VS Flink ——性能对比
1.背景 Apache Flink 和 Apache Storm 是当前业界广泛使用的两个分布式实时计算框架.其中 Apache Storm(以下简称"Storm")在美团点评实时 ...
- Apache Flink中的广播状态实用指南
感谢英文原文作者:https://data-artisans.com/blog/a-practical-guide-to-broadcast-state-in-apache-flink 不过,原文最近 ...
- State Processor API:如何读取,写入和修改 Flink 应用程序的状态
过去无论您是在生产中使用,还是调研Apache Flink,估计您总是会问这样一个问题:我该如何访问和更新Flink保存点(savepoint)中保存的state?不用再询问了,Apache Flin ...
- Flink 容错机制与状态
简介 Apache Flink提供了一种容错机制,可以持续恢复数据流应用程序的状态. 该机制确保即使出现故障,经过恢复,程序的状态也会回到以前的状态. Flink 主持 at least once 语 ...
- storm入门(二):关于storm中某一段时间内topN的计算入门
刚刚接触storm 对于滑动窗口的topN复杂模型有一些不理解,通过阅读其他的博客发现有两篇关于topN的非滑动窗口的介绍.然后转载过来. 下面是第一种: Storm的另一种常见模式是对流式数据进行所 ...
- Storm概念学习系列之什么是实时流计算?
不多说,直接上干货! 什么是实时流计算? 1.实时流计算背景 2.实时计算应用场景 3.实时计算处理流程 4.实时计算框架 什么是实时流计算? 所谓实时流计算,就是近几年由于数据得到广泛应用之后 ...
- 入门大数据---Flink学习总括
第一节 初识 Flink 在数据激增的时代,催生出了一批计算框架.最早期比较流行的有MapReduce,然后有Spark,直到现在越来越多的公司采用Flink处理.Flink相对前两个框架真正做到了高 ...
随机推荐
- Oracle 统计信息介绍
统计信息自动执行需要以下条件满足: dba_autotask_task 字段status值ENABLED dba_autotask_client 字段status值ENABLED dba_auto ...
- kuberenetes CRD开发指南
扩展kubernetes两个最常用最需要掌握的东西:自定义资源CRD 和 adminsion webhook, 本文教你如何十分钟掌握CRD开发. kubernetes允许用户自定义自己的资源对象,就 ...
- Waiting for 1 instance(s) to be deallocated
看是不是马虎,自己的xampp,也就是mysql有没有打开
- JS面向对象编程(三):非构造函数的继承
一.什么是"非构造函数"的继承? 现在有一个对象,叫"中国人". var Chinese = { ...
- 【Python3爬虫】当爬虫碰到表单提交,有点意思
一.写在前面 我写爬虫已经写了一段时间了,对于那些使用GET请求或者POST请求的网页,爬取的时候都还算得心应手.不过最近遇到了一个有趣的网站,虽然爬取的难度不大,不过因为表单提交的存在,所以一开始还 ...
- JAVA常用的集合类
package com.xian.test; import java.util.ArrayList; import java.util.Enumeration; import java.util.Ha ...
- 100天搞定机器学习|Day15 朴素贝叶斯
Day15,开始学习朴素贝叶斯,先了解一下贝爷,以示敬意. 托马斯·贝叶斯 (Thomas Bayes),英国神学家.数学家.数理统计学家和哲学家,1702年出生于英国伦敦,做过神甫:1742年成为英 ...
- 开发一个Spring Boot Starter!
在上一篇文章中,我们已经了解了一个starter实现自动配置的基本流程,在这一小结我们将复现上一过程,实现一个自定义的starter. 先来分析starter的需求: 在项目中添加自定义的starte ...
- 让 CXK 来教你实现游戏中的帧动画(上)
一款游戏除了基本功能之外,还需要给玩家更多视觉上的刺激,这个时候就需要用特效来装饰.本文就将介绍 Cocos Creator 的动画系统,除了标准的位移.旋转.缩放动画和序列帧动画以外,这套动画系统还 ...
- java 各基本类型转 bytes 数组
java 将 基本类型转byte[] 数组时,需考虑大端小端问题 1. 大端格式下,基本类型与byte[]互转 BigByteUtil.java package com.ysq.util; impor ...