流式计算Flink与其Exactly-Once语义实现

Flink及Storm、Spark主流流框架比较

Flink作为近年新起的大数据流式处理框架,正逐渐被各大企业采用而变为主流。其常常被用来与Storm、Spark streaming和kafak streaming等同类数据处理框架作对比,经大致总结,各框架特性与性能对比如下表:

框架StormSpark streamingKafka streamsFlink
模型批处理微批处理流式处理流式处理
保证处理语义At-Least-OnceAt-Least-OnceExactly-OnceExactly-Once
容错机制上游备份+ACK机制检查点机制幂等操作+事务异步屏障快照算法
延时
吞吐量
支持EventTime不支持不支持支持支持
支持状态计算不支持支持支持支持

从表中可以看出,Flink作为新一代的大数据处理框架与其他主流框架相比在很多方面皆具有优势。Flink在立项之初便致力于真正的实时流式计算,相较于传统的批处理,流式计算更贴近于现实世界的信息模式。同时随着如今越来越多的实时计算需求在各行业内展现,流式大数据计算引擎成为主流已是不可阻挡的趋势。总的来说,Flink相较于同类大数据处理引擎有以下明显优势:

1、轻量级异步屏障快照算法保证Exactly-Once
2、支持EventTime乱序事件处理
3、低延迟、高吞吐量
4、实现了流处理和批处理统一
5、支持有状态计算

异步屏障快照算法解析

异步屏障快照算法(asynchronous barrier snapshotting, ABS)为奠定Flink如今在大数据处理领域的地位起到了至关重要的作用,该算法由五位大佬通过论文《Lightweight Asynchronous Snapshots for Distributed Dataflows》提出。要理解ABS,首先要了解大数据计算领域的三种处理语义:

At-Most-Once
这是一种“尽力而为”的方法。数据或事件可以保证被应用程序中的所有运算符最多处理一次。这意味着如果在流应用程序最终成功处理之前就已丢失,则不会额外试图重试或重新传输事件。
至多一次

At-Least-Once
数据或事件可保证被应用程序图中的所有运算符最少处理一次。这通常意味着如果在流应用程序最终成功处理之前就已丢失,那么事件将从来源重播(Replayed)或重新传输。然而因为可以重新传输,有时候一个事件可能被多次处理,因此这种方式被称之为“最少一次”。下图展示了一个范例。在本例中,第一个运算符最初处理事件时失败了,随后重试并成功,随后再次重试并再次成功,然而再次重试实际上是不必要的。
至少一次
Exactly-Once
表示每一条数据恰好被处理一次,或可理解为无论计算过程正常或是有出错,最终计算结果都是一样正确的。

需要注意的是,上述所说的“处理一次”不能单纯地理解为数据只进行过一次计算,而是应该理解为数据只有效影响过一次计算结果。毕竟任何计算框架都不能保证数据在传输计算过程中不出错,也就不能保证数据只被真正计算过一次,就Exactly-Once而言,其实叫做Effective-Once,有效一次更为贴切。

是否实现Exactly-Once是衡量一个大数据处理框架的重要指标,因为只有达到Exactly-Once,才能真正保证计算结果准确无误,从而满足“金融级需求”,毕竟很多应用下数据计算的遗漏或者重算都是不可接受的。而在众多大数据处理框架实现Exactly-Once语义的方案中,Flink的ABS算法可以说是最优雅的一种。

保证Exactly-Once语义的主要思路是采用一定方式保存全局流和所有算子在某一检查点(checkpoint)的状态,即分布式快照(snapshot),并在错误发生后将全局状态重放到最近的检查点重新开始计算。但获得分布式快照是一件比较困难的事,因为流与计算过程都是持续进行的,若想保存某一时刻的全局状态,则需要暂停全局工作,在时停阶段生成快照。这种方式不仅会造成很高的延迟,并且因为要记录全局流和算子的状态,所需的存储消耗的也是较大的。而ABS算法之所以是轻量级的,就是因为其通过barrier屏障机制实现了动态过程中生成分布式快照,并只需存储最新计算记录、各算子状态和源的offset,花费很低的延时和存储代价便达到了Exactly-Once语义。接下来将详细解析ABS算法的原理。

Flink作业可以抽象成有向图表示,图的顶点是算子(operator),边是数据流(data stream),ABS算法建立在一下推论上:

    1、Flink作业的快照要包含两部分,即算子所处的状态以及数据流承载的数据。算子每收到/发出一条数据,以及数据流每流入/流出一条数据,都会造成全局状态的改变。
    2、算子可以感知到自己的状态,但数据流的状态不容易记录,主要是因为承载的数据量太大,并且总是在变化。
    3、时间是无法静止的(即数据总是在流动的),并且快照不能stop-the-world,否则会造成延迟和数据堆积,降低吞吐量。

其解决方案的要点有二:一是通过每个算子自己记录的状态合并出全局快照,二是引入一个标记把数据流从时域上切分成段。下面就可以了解ABS算法的基础——屏障Barrier。

屏障由Flink的JobManager周期性产生(周期长度由StreamExecutionEnvironment.enableCheckpointing()方法来指定),并广播给所有Source算子,沿着数据流流动下去。下图示出一条带有屏障的数据流。
在这里插入图片描述

可见,第n - 1个屏障之后、第n个屏障之前的所有数据都属于第n个检查点。下游算子如果检测到屏障的存在,就会触发快照动作,不必再关心时间无法静止的问题。下面继续了解快照阶段是如何执行的。举例说明检查点流程。下图是论文中给出的并行度为2的Word Count示例,注意该作业的执行计划为有向无环图(DAG)。
在这里插入图片描述
快照算法的步骤如下:

a)、 Source算子接收到JobManager产生的屏障,生成自己状态的快照(其中包含数据源对应的offset/position信息),并将屏障广播给下游所有数据流;

b)、下游非Source的算子从它的某个输入数据流接收到屏障后,会阻塞这个输入流,继续接收其他输入流,直到所有输入流的屏障都到达(图中的count-2算子接收的两个屏障就不是同时到达的)。实际上,为了防止输入流的背压(back-pressuring),BarrierBuffer并不是真正的阻塞这个流,而是将此channel中,barrier之后数据通过一个BufferSpiller来buffer起来,当channel的锁释放后,再从buffer读回这些数据,继续处理。在数据流从上游生产者向下游消费者传输的过程中,上游生产速度大于下游消费速度,导致下游的 Buffer 溢出,这种现象就叫做 Backpressure 出现。一旦算子收齐了所有屏障,它就会生成自己状态的快照,并继续将屏障广播给下游所有数据流;

c)、 快照生成后,算子解除对输入流的阻塞,继续进行计算。Sink算子接收到屏障之后会向JobManager确认,所有Sink都确认收到屏障标记着这一周期checkpoint过程结束,快照成功。

可见,如果算子只有一个输入流的话,问题就比较简单,只需要在收到屏障之后立即做快照。但是如果有多个输入流,就必须要等待收到所有屏障才能做快照,以避免将检查点n与检查点n + 1的数据混淆。这个等待的过程就叫做对齐(alignment),图来自官方文档。注意算子内部有个输入缓冲区,用来在对齐期间缓存数据。对齐操作保证了每条数据都被处理且仅被处理一次。

试想若无对齐操作,每个源的屏障到达后不做缓存继续流动,则当所有源的屏障到达算子并触发快照时,先到达的源流在本次屏障之后的数据已有部分被处理并影响了状态快照。当下次出现故障重放时,这部分数据将再次被处理影响算子状态,即变为了At-Least-Once。实际上Flink确实是用这种机制实现At-Least-Once语义的,当对计算精确性要求不高时,可在Flink配置CheckpointingMode为CheckpointingMode.AT_LEAST_ONCE(默认为CheckpointingMode.EXACTLY_ONCE),将Exactly-Once放宽为At-Least-Once,从而降低延迟。

“屏障”和“快照”都讲过了,“异步”呢?这个词实际上指的是快照数据写入的异步性:算子收齐屏障并触发快照之后,不会等待快照数据全部写入状态后端,而是一边后台写入,一边立刻继续处理数据流,并将屏障发送到下游,实现了最小化延迟。引入异步性之后,checkpoint成功的条件除了所有Sink都报告ack之外,还得加上一条:所有有状态的算子都报告ack,否则JobManager就无法确认异步写入到底完成没有。

上述snapshot完成后,当发生错误时,系统会回放到最近一次快照状态,即重置源流offset和各算子状态。想要通俗理解barrier机制生成的快照,可以想象各barrier将连续的数据流分为间隔的多段,每个检查点的snapshot记录了barrier区分的当前数据流的位置,以及barrier之前所有数据流对全局算子造成的最终影响。当重放快照时,所有barrier以前的历史数据都已被处理一次且造成了影响,所有barrier之后的数据流都还未被处理,由此保证了Exactly-Once语义。

漫谈Flink与阿里巴巴

扯点技术外的闲言碎语,Flink能在业界有今天的成就,离不开阿里巴巴对其的应用与支持。阿里于15年开始将Flink引入阿里社区。当时在典型的大数据的业务场景下数据业务最通用的做法是:选用批处理的技术处理全量数据,采用流式计算处理实时增量数据。在绝大多数的业务场景之下,用户的业务逻辑在批处理和流处理之中往往是相同的。但是,用户用于批处理和流处理的两套计算引擎是不同的。因此,用户通常需要写两套代码。毫无疑问,这带来了一些额外的负担和成本。

阿里巴巴的商品数据处理就经常需要面对增量和全量两套不同的业务流程问题,所以阿里就在想建立一套统一的大数据引擎技术,用户只需要根据自己的业务逻辑开发一套代码。这样在各种不同的场景下,不管是全量数据还是增量数据,亦或者实时处理,一套方案即可全部支持,这就是阿里选择Flink的背景和初衷。
在这里插入图片描述

开源大数据计算引擎有很多选择,流计算如Storm,Samza,Flink,Kafka Stream等,批处理如Spark,Hive,Pig,Flink等。而同时支持流处理和批处理的计算引擎,只有两种选择:一个是Apache Spark,一个是Apache Flink。从技术,生态等各方面的综合考虑。首先,Spark的技术理念是基于批来模拟流的计算。而Flink则完全相反,它采用的是基于流计算来模拟批计算。从技术发展方向看,用批来模拟流有一定的技术局限性,并且这个局限性可能很难突破。而Flink基于流来模拟批,在技术上有更好的扩展性。从长远来看,阿里决定用Flink做一个统一的、通用的大数据引擎作为未来的选型。

彼时的 Flink 不管是规模还是稳定性尚未经历实践,成熟度有待商榷。阿里巴巴实时计算团队决定在阿里内部建立一个 Flink 分支 Blink,并对 Flink 进行大量的修改和完善,不仅对Flink在性能和稳定性上做出了很多改进和优化,同时在核心架构和功能上也进行了大量创新和改进,并将其贡献给社区,例如:Flink新的分布式架构,增量Checkpoint机制,基于Credit-based的网络流控机制和Streaming SQL等。简单地说,Blink 就是阿里巴巴开发的基于开源 Flink 的阿里巴巴内部版本。

阿里巴巴基于 Flink 搭建的平台于 2016 年正式上线,并从阿里巴巴的搜索和推荐这两大场景开始实现。目前阿里巴巴所有的业务,包括阿里巴巴所有子公司都采用了基于 Flink 搭建的实时计算平台。Flink最初上线阿里巴巴只有数百台服务器,目前规模已达上万台,此等规模在全球范围内也是屈指可数;基于Flink,内部积累起来的状态数据已经是PB级别规模;如今每天在Flink的计算平台上,处理的数据已经超过万亿条;在峰值期间可以承担每秒超过4.72亿次的访问,最典型的应用场景是阿里巴巴双11大屏。
在这里插入图片描述可以说阿里的对Flink的商业实践就是其在实时大数据处理领域的一块金子招牌,并且阿里也在不断积极地完善拓展Blink,同时致力于将其贡献回Flink社区,促进Flink发展。19年一月,阿里收购了Flink母公司Data Artisans,并宣布将Blink开源,随后又宣布了阿里Blink与Flink的合并计划,可以说今后Flink的发展将与阿里社区密不可分。

相关资料:

深入理解Flink的轻量级异步屏障快照(ABS)算法
解读Flink中轻量级的异步快照机制
谈谈流计算中的『Exactly Once』特性
流式处理 术语解释 Exactly-once与Effectively-once
简单解释: 分布式快照(Chandy-Lamport算法)
阿里重磅开源Blink:为什么我们等了这么久?
Spark Stream、Kafka Stream、Storm和Flink对比,以及阿里巴巴基于Flink打造的Blink解决的问题
阿里巴巴为什么选择Apache Flink?
漫谈加持Blink的Flink和Spark
开源的Blink和Spark3.0,谁将称霸大数据领域?

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值