王海涛,曾经在微软的 SQL Server和大数据平台组工做多年。带领团队创建了微软对内的 Spark 服务,主打 Spark Streaming。去年加入阿里实时计算部门,参与改进阿里基于 Apache Flink 的Blink 平台。html
导读: 作大数据绝对躲不过的一个热门话题就是实时流计算,而提到实时流计算,就不得不提 Spark 和 Flink。Spark 从 2014 年左右开始迅速流行,刚推出时除了在某些场景比 Hadoop MapReduce 带来几十到上百倍的性能提高外,还提出了用一个统一的引擎支持批处理、流处理、交互式查询、机器学习等常见的数据处理场景。凭借高性能和全面的场景支持,Spark 早已成为众多大数据开发者的最爱。数据库
正在 Spark 如日中天高速发展的时候,2016 年左右 Flink 开始进入大众的视野并逐渐广为人知。在人们开始使用 Spark 以后,发现 Spark 虽然支持各类常见场景,但并非每一种都一样好用。数据流的实时处理就是其中相对较弱的一环。Flink 凭借更优的流处理引擎,同时也支持各类处理场景,成为 Spark 的有力挑战者。固然,Spark 也在不断加强其实时流处理能力,在今年 2 月份发布的 2.3 版本中引入了持续流式处理模型,可将流处理延迟下降至毫秒级别。apache
本文对 Spark 和 Flink 的技术与场景进行了全面分析与对比,且看下一代大数据计算引擎之争,谁主沉浮?编程
自从数据处理需求超过了传统数据库能有效处理的数据量以后,Hadoop 等各类基于 MapReduce 的海量数据处理系统应运而生。从2004 年 Google 发表 MapReduce 论文开始,通过近10年的发展,基于 Hadoop 开源生态或者其它相应系统的海量数据处理已经成为业界的基本需求。api
可是,不少机构在开发本身的数据处理系统时都会发现须要面临一系列的问题。从数据中获取价值须要的投入远远超过预期。常见的问题包括:网络
上图是一个典型的lambda架构,只是包含了批处理和流处理两种场景,就已经牵涉到至少四五种技术了,还不算每种技术的可替代选择。再加上实时查询,交互式分析,机器学习等场景,每一个场景都有几种技术能够选择,每一个技术涵盖的领域还有不一样方式的重叠。结果就是一个业务常常须要使用四五种以上的技术才能支持好一个完整的数据处理流程。加上调研选型,须要了解的数目还要多得多。架构
下图是大数据领域的全景。有没有晕?运维
开发和运行效率低下。由于牵涉到多种系统,每种系统有本身的开发语言和工具,开发效率可想而知。而由于采用了多套系统,数据须要在各个系统之间传输,也形成了额外的开发和运行代价,数据的一致也难以保证。在不少机构,实际上一半以上的开发精力花在了数据在各个系统之间的传输上。机器学习
复杂的运维。多个系统,每一个须要本身的运维,带来更高的运维代价的同时也提升了系统出问题的可能。异步
数据质量难以保证。数据出了问题难以跟踪解决。
最后,还有人的问题。在不少机构,因为系统的复杂性,各个子系统的支持和使用落实在不一样部门负责。
了解了这些问题之后,对Spark 从2014年左右开始迅速流行就比较容易理解了。Spark 在当时除了在某些场景比 Hadoop MapReduce 带来几十到上百倍的性能提高外,还提出了用一个统一的引擎支持批处理,流处理,交互式查询,机器学习等常见的数据处理场景。看过在一个 Notebook 里完成上述全部场景的 Spark 演示,对比以前的数据流程开发,对不少开发者来讲不难作出选择。通过几年的发展,Spark 已经被视为能够彻底取代 Hadoop 中的 MapReduce 引擎。
正在 Spark 如日中天高速发展的时候,2016年左右 Flink 开始进入大众的视野并逐渐广为人知。为何呢?原来在人们开始使用 Spark 以后,发现 Spark 虽然支持各类场见场景,但并非每一种都一样好用。数据流的实时处理就是其中相对较弱的一环。Flink 凭借更优的流处理引擎,同时也支持各类处理场景,成为 Spark 的有力挑战者。
Spark 和 Flink 是怎么作到这些的,它们之间又有那些异同,下面咱们来具体看一下。
这一部分主要着眼于 Spark 和 Flink 引擎的架构方面,更看重架构带来的潜力和限制。现阶段的实现成熟度和局限会在后续生态部分探讨。
要理解 Spark 和 Flink 的 引擎特色,首先从数据模型开始。
Spark 的数据模型是弹性分布式数据集 RDD(Resilient Distributed Datasets)。 比起 MapReduce 的文件模型,RDD是一个更抽象的模型,RDD 靠血缘(lineage) 等方式来保证可恢复性。不少时候RDD能够实现为分布式共享内存或者彻底虚拟化(即有的中间结果 RDD 当下游处理彻底在本地时能够直接优化省略掉)。这样能够省掉不少没必要要的I/O,是早期 Spark 性能优点的主要缘由。
Spark 用 RDD 上的变换(算子)来描述数据处理。每一个算子(如 map,filter,join)生成一个新的 RDD。全部的算子组成一个有向无环图(DAG)。Spark 比较简单地把边分为宽依赖和窄依赖。上下游数据不须要 shuffle 的即为窄依赖,能够把上下游的算子放在一个阶段(stage) 里在本地连续处理,这时上游的结果 RDD能够 省略。下图展现了相关的基本概念。更详细的介绍在网上比较容易找到,这里就不花太多篇幅了。
Flink 的基本数据模型是数据流,及事件(Event) 的序列。数据流做为数据的基本模型可能没有表或者数据块直观熟悉,可是能够证实是彻底等效的。流能够是无边界的无限流,即通常意义上的流处理。也能够是有边界的有限流,这样就是批处理。
Flink 用数据流上的变换(算子)来描述数据处理。每一个算子生成一个新的数据流。在算子,DAG,和上下游算子连接(chaining) 这些方面,和 Spark 大体等价。Flink 的节点(vertex)大体至关于Spark 的阶段(stage),划分也会和上图的 Spark DAG 基本同样。
在 DAG的执行上,Spark 和 Flink 有一个比较显著的区别。 在Flink 的流执行模式中,一个事件在一个节点处理完后的输出就能够发到下一个节点当即处理。这样执行引擎并不会引入额外的延迟。与之相应的,全部节点是须要同时运行的。而 Spark 的 micro batch 和通常的batch 执行同样,处理完上游的 stage 获得输出以后才开始下游的 stage。
在Flink的流执行模式中,为了提升效率也能够把多个事件放在一块儿传输或者计算。但这彻底是执行时的优化,能够在每一个算子独立决定,也不用像 RDD 等批处理模型中同样和数据集边界绑定,能够作更加灵活的优化同时能够兼顾低延迟需求。
Flink 使用异步的 checkpoint 机制来达到任务状态的可恢复性,以保证处理的一致性,因此在处理的主流程上能够作到数据源和输出之间数据彻底不用落盘,达到更高的性能和更低的延迟。
除了批处理以外,Spark 还支持实时数据流处理,交互式查询,和机器学习,图计算等。
实时数据流处理和批处理主要区别就是对低延时的要求。Spark 由于 RDD 是基于内存的,能够比较容易切成较小的块来处理。若是能对这些小块处理得足够快,就能达到低延时的效果。
交互式查询场景,若是数据能全在内存,处理得足够快的话,就能够支持交互式查询。
机器学习和图计算实际上是和前几种场景不一样的 RDD 算子类型。Spark 提供了库来支持经常使用的操做,用户或者第三方库也能够本身扩展。值得一提的是,Spark 的 RDD 模型和机器学习模型训练的迭代计算很是契合,从一开始就在有的场景带来了很是显著的性能提高。
从这些能够看出来,比起 Hadoop MapReduce, Spark 本质上就是基于内存的更快的批处理。而后用足够快的批处理来实现各类场景。
前面说过,在Flink 中,若是输入数据流是有边界的,就天然达到了批处理的效果。这样流和批的区别彻底是逻辑上的,和处理实现独立,用户须要实现的逻辑也彻底同样,应该是更干净的一种抽象。后续会在深刻对比流计算方面的时候作更深刻的讨论。
Flink 也提供了库来支持机器学习,图计算等场景。从这方面来讲和 Spark 没有太大区别。
一个有意思的事情是用 Flink 的底层 API 能够支持只用 Flink集群实现一些数据驱动的分布式服务。有一些公司用 Flink集群实现了社交网络,网络爬虫等服务。这个也体现了 Flink 做为计算引擎的通用性,并得益于 Flink 内置的灵活的状态支持。
总的来讲,Spark 和 Flink 都瞄准了在一个执行引擎上同时支持大多数数据处理场景,也应该都能作到这一点。主要区别就在于由于架构自己的局限在一些场景会受到限制。比较突出的地方就是 Spark Streaming 的 micro batch 执行模式。Spark 社区应该也意识到了这一点,最近在持续执行模式(continuous processing)方面开始发力。 具体状况会在后面介绍。
Flink 还有一个很是独特的地方是在引擎中引入了托管状态(managed state)。要理解托管状态,首先要从有状态处理提及。若是处理一个事件(或一条数据)的结果只跟事件自己的内容有关,称为无状态处理;反之结果还和以前处理过的事件有关,称为有状态处理。稍微复杂一点的数据处理,好比说基本的聚合,都是有状态处理。Flink 很早就认为没有好的状态支持是作很差留处理的,所以引入了 managed state 并提供了 API接口。
通常在流处理的时候会比较关注有状态处理,可是仔细看的话批处理也是会受到影响的。好比常见的窗口聚合,若是批处理的数据时间段比窗口大,是能够不考虑状态的,用户逻辑常常会忽略这个问题。可是当批处理时间段变得比窗口小的时候,一个批的结果实际上依赖于之前处理过的批。这时,由于批处理引擎通常没有这个需求不会有很好的内置支持,维护状态就成为了用户须要解决的事情。好比窗口聚合的状况用户就要加一个中间结果表记住尚未完成的窗口的结果。这样当用户把批处理时间段变短的时候就会发现逻辑变复杂了。这是早期 Spark Streaming 用户 常常碰到的问题。直到 Structured Streaming 出来才获得缓解。
而像 Flink 这样以流处理为基本模型的引擎,由于一开始就避不开这个问题,因此引入了 managed state 来提供了一个通用的解决方案。比起用户实现的特定解决方案,不但用户开发更简单,并且能提供更好的性能。最重要的是能更好地保证处理结果的一致性。
简单来讲,就是有一些內秉的数据处理逻辑,在批处理中容易被忽略或简化处理掉也能获得可用的结果,而在流处理中问题被暴露出来解决掉了。因此流计算引擎用有限流来处理批在逻辑上比较严谨,能天然达到正确性。主要作一些不一样的实现来优化性能就能够了。而用更小的批来模拟流须要处理一些之前没有的问题。当计算引擎尚未通用解决方案的时候就须要用户本身解决了。相似的问题还有维表的变化(好比用户信息的更新),批处理数据的边界和迟到数据等等。
Spark 的初衷之一就是用统一的编程模型来解决用户的各类需求。在这方面一直很下功夫。最初基于 RDD 的 API 就能够作各类类型的数据处理。后来为了简化用户开发,逐渐推出了更高层的DataFrame(在 RDD 中加了列变成结构化数据)和 Datasets(在 DataFrame 的列上加了类型),并在Spark 2.0 中作了整合(DataFrame = DataSet[Row])。Spark SQL 的支持也比较早就引入了。在加上各个处理类型API 的不断改进,好比 Structured Streaming 以及和机器学习深度学习的交互,到了今天Spark 的 API 能够说是很是好用的,也是 Spark 最强的方面之一。
Flink 的API也有相似的目标和发展路线。Flink 和 Spark 的核心 API 能够说是能够基本对应的。今天Spark API 整体上更完备一下,好比说最近一两年大力投入的和机器学习深度学习的整合方面。Flink 在流处理相关的方面仍是领先一些,好比对 watermark,window,trigger 的各类支持。
Spark 和 Flink 都是通用的可以支持超大规模数据处理,支持各类处理类型的计算引擎。两个系统都有不少值得探讨的方面在这里没有触及,好比 SQL 的优化,和机器学习的集成等等。这里主要是试图从最基本的架构和设计方面来比较一下两个系统。由于上层的功能在必定程度上是能够互相借鉴的,有足够的投入应该都能作好。而基本的设计改变起来会伤筋动骨,更困难一些。
Spark 和 Flink 的不一样执行模型带来的最大的区别应该仍是在对流计算的支持上。最开始的 Spark Streaming 对流计算想得过于简单,对复杂一点的计算用起来会有很多问题。从 Spark 2.0 开始引入的 Structured Streaming 从新整理了流计算的语义,支持按事件时间处理和端到端的一致性。虽然在功能上还有很多限制,比以前已经有了长足的进步。不过 micro batch 执行方式带来的问题仍是存在,特别在规模上去之后性能问题会比较突出。最近 Spark 受一些应用场景的推进,也开始开发持续执行模式。2.3里的实验性发布还只支持简单的 map 类的操做。 Spark 持续执行模式状态(来源:www.slideshare.net/databricks/…
从最近 Spark+AI Summit 大会上的介绍来看(下图),会发展成一个和 Flink 的流处理模式比较类似的执行引擎。不过从下图来看,主要的功能都还在开发中或者待开发。对未来能作到什么程度,和 Spark 原来的 batch 执行引擎怎么结合,咱们拭目以待。
更多资讯请访问 Apache Flink 中文社区网站