exactlyonce
2Storm
提供了低延迟的流处理,但是它为实时性付出了一些代价:很难实现高吞吐,并且其正确性没能达到通常所需的水平。换句话说,它并不能保证exactlyonce
;即便是它能够保证的正确性级别,其开销也相当大图12:
Flink
的一个优势是,它拥有诸多重要的流式计算功能。其他项目为了实现这些功能,都不得不付出代价。比如,Storm
实现了低延迟,但是在作者撰写本书时还做不到高吞吐,也不能在故障发生时准确地处理计算状态;SparkStreaming
通过采用微批处理方法实现了高吞吐和容错性,但是牺牲了低延迟和实时处理能力,也不能使窗口与自然时间相匹配,并且表现力欠佳
ApacheFlink
是为分布式、高性能、随时可用以及准确的流处理应用程序打造的开源流处理框架。”Flink
不仅能提供同时支持高吞吐和exactlyonce
语义的实时计算,还能提供批量数据处理flink
一词表示快速和灵巧。项目采用一只松鼠的彩色图案作为logo
,这不仅因为松鼠具有快速和灵巧的特点,还因为柏林的松鼠有一种迷人的红棕色Apache
软件基金会的顶级项目。作为Apache
软件基金会的5个最大的大数据项目之一,Flink
在全球范围内拥有200多位开发人员,以及若干公司中的诸多上线场景,有些甚至是世界500强的公司Flink
是如何同时实现批处理与流处理的呢?答案是,Flink
将批处理(即处理有限的静态数据)视作一种特殊的流处理FlinkRuntime
执行引擎可以作为YARN
(YetAnotherResourceNegotiator
)的应用程序在集群上运行,也可以在Mesos
集群上运行,还可以在单机上运行(这对于调试Flink
应用程序来说非常有用)图14:
Flink
技术栈的核心组成部分。值得一提的是,Flink
分别提供了面向流处理的接口(DataStreamAPI
)和面向批处理的接口(DataSetAPI
)。因此,Flink
既可以完成流处理,也可以完成批处理。Flink
支持的拓展库涉及机器学习(FlinkML
)、复杂事件处理(CEP
),以及图计算(Gelly
),还有分别针对流处理和批处理的TableAPI
Flink
解决了许多问题,比如保证了exactlyonce
语义和基于事件时间的数据窗口。开发人员不再需要在应用层解决相关问题,这大大地降低了出现bug
的概率布衣格电信 支持真正的流处理——通过上层的
API
和下层的执行引擎都能实时进行流处理,这满足了我们对可编程性和低延迟的需求。此外,使用Flink
,我们的系统得以快速上线,这是其他任何一种方案都做不到的。如此一来,我们就有了更多的人手开发新的业务逻辑
ETL
是Extract
、Transform
和Load
的缩写,即抽取、转换和加载Flink
中获益呢?一个常见的做法是设置消息传输层和流处理层图21:
Flink
项目的架构有两个主要组成部分:消息传输层和由Flink
提供的流处理层。消息传输层负责传输连续事件产生的消息,能够提供消息传输的系统包括Kafka
和MapRStreams
。MapRStreams
是MapR
融合数据平台的一个主要组成部分,它兼容KafkaAPI
Kafka
和MapRStreams
都可以满足这个需求Flink
解决了可能影响正确性的几个问题,包括如何在故障发生之后仍能进行有状态的计算Flink
所用的技术叫作检查点(checkpoint
)Flink
还承担了跟踪计算状态的任务,从而减轻了开发人员的负担,简化了编程工作,并提高了应用程序的成功率。用同一种技术来实现流处理和批处理,大大地简化了开发和运维工作key
将事件分组,并且每隔一段时间(比如一小时)就针对每一个key
对应的事件计数。这是众所周知的“大数据”应用,与MapReduce
的词频统计例子相似API
的一部分。否则,系统将受到限制,并且变得脆弱且难以使用图4-4:事件时间顺序与处理时间顺序不一致的乱序事件流
图45:一分钟滚动窗口计算最近一分钟的数值总和
图46:一分钟滑动窗口每半分钟计算一次最近一分钟的数值总和
Flink
中,一分钟滚动窗口的定义如下Flink
支持的另一种常见窗口叫作计数窗口。采用计数窗口时,分组依据不再是时间戳,而是元素的数量。例如,图46中的滑动窗口也可以解释为由4个元素组成的计数窗口,并且每两个元素滑动一次。滚动和滑动的计数窗口分别定义如下Flink
支持的另一种很有用的窗口是会话窗口Flink
内部,所有类型的窗口都由同一种机制实现Kafka
和MapRStreams
这样的现代传输层,支持时空穿梭,这使得它们与更早的解决方案有所区别Flink
通过水印来推进事件时间。水印是嵌在流中的常规记录,计算程序通过水印获知某个时间点已到Flink
中,水印由应用程序开发人员生成,这通常需要对相应的领域有一定的了解。完美的水印永远不会错:时间戳小于水印标记时间的事件不会再出现Flink
作业监控事件流,学习事件的迟到规律,并以此构建水印生成模型图48展示了爱立信团队构建的数据管道
Kafka
的原始数据是来自云基础设施中的所有实体机和虚拟机的遥测信息和日志事件。它们经过不同的Flink
作业消费之后,被写回Kafka
主题里,然后再从Kafka
主题里被推送给搜索引擎Elasticsearch
和可视化系统Kibana
。这种架构让每个Flink
作业所执行的任务有清晰的定义,一个作业的输出可以成为另一个作业的输入图5-1:无状态流处理与有状态流处理的区别。输入记录由黑条表示。无状态流处理每次只转换一条输入记录,并且仅根据最新的输入记录输出结果(白条)。有状态流处理维护所有已处理记录的状态值,并根据每条新输入的记录更新状态,因此输出记录(灰条)反映的是综合考虑多个事件之后的结果
atmostonce
:这其实是没有正确性保障的委婉说法——故障发生之后,计数结果可能丢失atleastonce
:这表示计数结果可能大于正确值,但绝不会小于正确值。也就是说,计数程序在发生故障后可能多算,但是绝不会少算exactlyonce
:这指的是系统保证在发生故障后得到的计数结果与正确值一致Flink
的一个重大价值在于,它既保证了exactlyonce
,也具有低延迟和高吞吐的处理能力图5-2:数环状项链上的珠子看上去毫无意义(甚至有些徒劳无功,因为可以永不停歇地计数),但是它可以用来很好地类比处理永不结束的事件流。在某些文化中,人们仍旧将数珠子视作消磨时间的好方法
keyBy
算子用来将记录按照第一个元素(一个字符串)进行分组,根据该key
将数据进行重新分区,然后将记录再发送给下一个算子:有状态的map
算子(mapWithState
)。map
算子在接收到每个元素后,将输入记录的第二个字段的数据加到现有总数中,再将更新过的元素发射出去图5-3:程序的初始状态。注意,
a
、b
、c
三组的初始计数状态都是0,即三个圆柱上的值。ckpt
表示检查点屏障。每条记录在处理顺序上严格地遵守在检查点之前或之后的规定,例如["b
",2]在检查点之前被处理,["a
",2]则在检查点之后被处理
图5-4:当
Flink
数据源(在本例中与keyBy
算子内联)遇到检查点屏障时,它会将其在输入流中的位置保存到稳定存储中。这让Flink
可以根据该位置重启输入
图5-6:检查点操作完成,状态和位置均已备份到稳定存储中。输入流中的所有记录都已处理完成。值得注意的是,备份的状态值与实际的状态值是不同的。备份反映的是检查点的状态
Flink
检查点算法的正式名称是异步屏障快照(asynchronousbarriersnapshotting
)。该算法大致基于ChandyLamport
分布式快照算法Flink
自动生成,用来在故障发生时重新处理记录,从而修正状态。Flink
用户还可以通过另一个特性有意识地管理状态版本,这个特性叫作保存点(savepoint
)Flink
命令行工具或者Web
控制台手动触发,而不由Flink
自动触发。和检查点一样,保存点也被保存在稳定存储中图5-9:手动触发的保存点(以圆圈表示)在不同时间捕获正在运行的
Flink
应用程序的状态
图5-10:使用保存点更新
Flink
应用程序的版本。新版本可以从旧版本生成的一个保存点处开始执行
Flink
版本更新A/B
测试图5-11:在该应用程序架构中,有状态的 Flink 应用程序消费来自消息队列的数据,然后将数据写入输出系统,以供查询 。底部的详情图展示 了 Flink 应用程序的内部情况
图5-14:Yahoo!Streaming Benchmark 结果。横轴表示每秒的事件吞吐量,以千为单位。纵轴表示端到端的99百分位数延迟,以秒为单位。 在性能测评中,Spark Streaming 遇到了吞吐量和延迟性难两全的问题。随着批处理作业规模的增加,延迟升高。如果为了降低延迟而缩减规模,吞吐量就会减少。Storm 和 Flink 则可以在吞吐量增加时维持低延迟
图5-16:使用高吞吐数据生成器的结果
exactly-once
和高可用性图64:分布式排序的处理阶段