这是数据处理引擎的发电站,它们正竞相定义下一个大数据时代
当涉及到大数据时,流计算和它所带来的实时强大分析的重要性是不可避免的。此外,当涉及到流计算时,无法避免该领域最强大的两种数据处理引擎:Spark和Flink。
自2014年以来,Apache Spark的受欢迎程度迅速上升,在某些情况下,它的性能超过了Hadoop MapReduce的三位数,提供了一个统一的引擎,支持所有常见的数据处理场景,如批处理、流处理、交互查询和机器学习。凭借其高性能和全面的场景支持,它在大数据开发中继续受到早期采用者的青睐。
在Spark出现后不久,Apache Flink作为一个外部挑战者开始进入公众视野,直到2016年才广为人知。早期的Spark用户在实时流处理等场景中遇到可用性问题时,Flink提供了一个高级流处理引擎,它支持广泛的场景以及其他优势。
在他们短暂的竞争中,Spark一直在优化它的实时流媒体功能,2.3版本(2月份发布)引入了连续处理模型,将流处理延迟降低到毫秒。Flink同样是一个令人敬畏的创新者,这两种架构中哪一种将最终主导下一代大数据计算还有待观察。
通过对它们各自技术和用途的综合分析,本文应该有助于阐明这一问题。
大数据计算引擎的起源
Hadoop和其他基于mapreduce的数据处理系统的出现首先是为了满足传统数据库无法满足的数据处理需求。随着2004年谷歌发布MapReduce白皮书以来的发展浪潮,利用Hadoop的开源生态系统或类似系统处理大数据已经成为行业的基本需求。
尽管最近努力降低进入门槛,但在开发自己的数据处理系统时,组织不可避免地会遇到一系列问题,常常会发现从数据中获得价值所需的投资大大超出预期。
下面的章节将详细介绍这些问题中最普遍的部分,这有助于解释Spark和Flink继续竞争行业偏好的基础。
非常陡峭的学习曲线
刚接触大数据的人通常会对需要掌握的技术数量感到震惊。过去几十年发展起来的传统数据库一般都是为了综合数据处理而构建的,而像Hadoop这样的大数据生态系统需要几个不同的子系统,每个子系统在呈现各种需求场景之前都有自己的专长和优势。
上面的图片描述了一个典型的lambda架构。仅仅展示了两种场景(批处理和流处理),它已经涉及了至少四到五种技术,不包括经常需要考虑的替代方案。通过添加实时查询、交互分析、机器学习和其他场景,每种情况都涉及到以不同方式覆盖重叠区域的几种技术之间的选择。因此,业务通常需要使用许多技术来支持完整的数据处理。再加上研究和选择,投资者需要消化的信息量是巨大的。
为了了解可用的技术,请考虑以下对大数据行业的概述。
开发运营效率低下
由于涉及的系统种类繁多,每个系统都有自己的开发工具和语言,大数据的开发效率在默认情况下相当有限。由于数据需要在多个系统之间传输,进一步的开发和操作成本不可避免地会出现。同时,数据一致性仍然难以保证。
在许多组织中,超过一半的开发工作花费在系统之间的数据传输上。
操作复杂、数据质量等问题
多个系统,每个系统都需要自己的操作和维护,带来较高的运行成本,增加系统出错的可能性。此外,很难保证数据的质量,而且当问题确实出现时,很难跟踪和解决它们。
最后但并非最不重要的,还有人的问题。在许多情况下,系统的复杂性意味着对每个子系统的支持和使用必须在不同的部门中实现,这些部门并不总是与目标和优先级保持一致。
到一个解决方案
鉴于这些问题,不难理解Spark的受欢迎程度。在其2014年崛起之时,Spark不仅增强了Hadoop MapReduce的性能,而且还提供了一个通用引擎来支持各种数据处理场景。在一个笔记本中看到一个Spark演示程序与上述所有场景一起工作,对于许多开发人员来说,转向Spark是一个相对容易的决定。因此,Spark作为Hadoop中的MapReduce引擎的完全替代品出现也就不足为奇了。
与此同时,Flink的出现是为了在一系列场景中提供更方便的使用,特别是在数据流的实时处理方面。
随着竞赛领域的建立,下面的部分将在技术层面上比较这两种竞争的框架。
在Spark和Flink中处理引擎
本节重点讨论Spark和Flink引擎的架构特性,重点讨论它们架构的潜力和局限性。和它们的数据和处理模型一样,它们在数据处理场景、有状态处理方法和编程模型中的重点是不同的。
数据模型和处理模型
要了解Spark和Flink中的引擎特性,首先必须检查它们各自的数据模型。
Spark使用弹性分布式数据集(RDD)数据模型。RDD比MapReduce的文件模型更抽象,它依赖沿袭来确保可恢复性。RDD通常可以实现为分布式共享内存或完全虚拟化。这就是说,当下游处理完全是本地的时候,可以优化和省略某些中间结果RDD。这节省了大量不必要的输入和输出,这是Spark早期性能优势的主要基础。
Spark还在RDD上使用转换(操作符)来描述数据处理。每个操作符(如map、filter、join)都会生成一个新的RDD。所有的算子一起构成一个有向无环图(DAG)。Spark简单地将边缘划分为宽依赖项和窄依赖项。当上游和下游数据不需要洗牌时,边缘是一个狭窄的依赖项。在这种情况下,上游和下游算子可以在同一阶段进行本地处理,可以省去上游结果RDD的物化。下图显示了所涉及的基本概念。
相比之下,Flink的基本数据模型是由数据流组成的。,事件的顺序。作为数据的基本模型,数据流可能不像表或数据块那样直观和熟悉,但仍然可以提供一组完全等价的特性。一条小溪可以是一条无限的小溪,是无限的,这是普遍的感知。它也可以是有边界的有限流,处理这些流等同于批处理。
为了描述数据处理,Flink在数据流上使用操作符,每个操作符生成一个新的数据流。在运营商、DAGs和上下游运营商链方面,整个模型与Spark模型大致相同。Flink的顶点与Spark中的阶段大致相同,将操作符划分为顶点与上图中Spark DAG中的划分阶段基本相同。
Spark和Flink在DAG执行方面有一个显著的区别。在Flink的流执行模式中,在一个节点上处理后的事件输出可以发送到下一个节点进行立即处理。这样执行引擎就不会引入任何额外的延迟。相应地,所有节点需要同时运行。相反,Spark的微批处理执行与正常的批处理执行没有区别,只有在上游阶段完成微批处理后,下游阶段才开始处理其输出。
在Flink的流执行模式中,可以一起传输或计算多个事件以提高效率。然而,这纯粹是执行引擎自行决定的优化。它可以独立地为每个操作符确定,并且不像批处理模型中那样绑定到数据集(如RDD)的任何边界。它可以为优化留下灵活性,同时满足低延迟需求。
Flink使用异步检查点机制来实现任务状态的可恢复性,以确保处理一致性。因此,可以消除数据源和输出之间的整个主处理路径上的I/O延迟,从而实现更高的性能和更低的延迟。
数据处理方案
除了批处理,Spark还支持实时数据流处理、交互式查询、机器学习和图形计算等场景。
实时数据流处理和批处理之间的主要区别是低延迟要求。因为Spark RDD是基于内存的,所以可以很容易地将其切割成更小的块进行处理。快速处理这些小块可以实现低延迟。
如果所有数据都在内存中并且处理速度足够快,Spark还可以支持交互式查询。
Spark的机器学习和图形计算可以看作是不同类别的RDD操作符。Spark提供了一些库来支持常见的操作,用户或第三方库还可以扩展并提供更多的操作。值得一提的是,Spark的RDD模型与机器学习模型训练的迭代计算非常兼容。从一开始,它就在一些场景中带来了显著的性能改进。
基于这些特性,Spark本质上是一个比Hadoop MapReduce更快的基于内存的批处理程序,它使用足够快的批处理来实现各种场景。
在Flink中,如果输入数据流是有界的,则批处理的效果自然会产生。流处理和批处理之间的区别仅在于输入类型,并且独立于底层实现和优化,因此用户需要实现的逻辑是完全相同的,从而产生一种更清晰的抽象。
Flink还提供了一些库来支持机器学习和图形计算等场景。在这方面,它与Spark并没有太大的区别。
值得注意的是,Flink的低级API可以单独使用Flink集群来实现一些数据驱动的分布式服务。一些公司使用Flink集群来实现社交网络、web爬行和其他服务。这些用途反映了Flink作为通用计算引擎的多功能性,并得益于Flink的内置状态支持。
通常,Spark和Flink的目标都是在单个执行引擎中支持大多数数据处理场景,并且都应该能够实现这一点。主要的区别在于,在某些场景中,它们各自的体系结构可能会受到限制。这种情况的一个值得注意的地方是Spark流的微批处理执行模式。Spark社区应该已经意识到这一点,并且最近开始致力于持续处理。我们稍后会回到这个问题。
有状态的处理
Flink的另一个非常独特的方面是在引擎中引入了托管状态。要理解托管状态,我们必须首先从有状态处理开始。如果处理事件(或数据片段)的结果只与事件本身的内容相关,则称为无状态处理;否则,结果与之前处理的事件相关,称为有状态处理。任何重要的数据处理,例如基本聚合,通常都是有状态处理。Flink一直认为,如果没有良好的状态支持,就不会有有效的流,因此,托管状态和状态API很早就被引入了。
通常,有状态处理是在流的上下文中考虑的,但是仔细看看它也会影响批处理。以窗口聚合的常见情况为例,如果批处理数据周期大于窗口,则可以忽略中间状态,用户逻辑容易忽略这个问题。然而,当批处理周期小于窗口时,批处理的结果实际上依赖于之前处理过的批处理。因为批处理引擎通常看不到这种需求,所以它们通常不提供内置状态支持,需要用户手动维护状态。例如,在窗口聚合的情况下,用户将需要一个中间结果表来存储不完整窗口的结果。因此,当用户缩短批处理周期时,处理逻辑就变得更加复杂。在结构化流发布之前,这是早期Spark流用户的一个常见问题。
另一方面,作为流媒体引擎的Flink从一开始就必须面对这个问题,并引入了托管状态作为通用解决方案。除了简化用户的工作之外,与用户实现的解决方案相比,内置解决方案还可以实现更好的性能。最重要的是,它可以提供更好的一致性保证。
简单地说,数据处理逻辑中存在一些固有的问题,在批处理中可以忽略或简化而不影响结果,但在流处理中会暴露并解决这些问题。因此,在流引擎中以有限流的形式实现批处理,自然会产生正确的结果,而主要的工作是为了优化而在某些领域进行专门的实现。相反,小批量模拟流场则会暴露出新的问题。当计算引擎没有一个问题的通用解决方案时,它需要用户自己解决它。除了状态之外,问题还包括维度表更改(如更新用户信息)、批处理数据边界、延迟到达的数据等等。
编程模型
Spark最初的意图之一是提供一个统一的编程模型,能够解决不同用户的各种需求——这是它投入了大量精力的一个重点。Spark最初的基于rd的API已经能够进行各种数据处理。后来,为了简化用户的开发,在Spark 2.0 (DataFrame = Dataset [Row])中引入并整合了更高级别的DataFrame(在RDD中向结构化数据中添加列)和Dataset(向DataFrame列添加类型)。Spark SQL支持也相对较早地引入。随着特定于场景的api的不断改进,比如结构化流以及与机器学习和深度学习的集成,Spark的api变得非常容易使用,现在已经成为该框架最强大的方面之一。
Flink的API遵循了一组类似的目标和开发路径。Flink和Spark的核心api可以看作是粗略的对应。在过去的两年里,通过对机器学习和深度学习的集成,Spark的API总体上更加完整。Flink仍然领先于流相关方面,例如它对水印、窗口和触发器的支持。
要点
Spark和Flink都是通用计算引擎,支持非常大规模的数据处理和各种类型的处理。每一篇文章都提供了很多这里没有涉及的内容,比如SQL优化和机器学习集成。这种比较的主要目的是回顾这两个系统的基本架构和设计特性。其基本原理是,更实际的做法是通过协作学习来赶上更高级别的功能,而在基本设计中进行更改往往代价更大,也更令人望而却步。
Spark和Flink不同的执行模型之间的最大区别在于它们对流处理的支持。最初Spark流处理的方法过于简单,在更复杂的处理中出现了问题。Spark 2.0中引入的结构化流,清理了流语义,并增加了对事件时处理和端到端一致性的支持。尽管在功能方面仍有许多限制,但它在过去的迭代中取得了相当大的进展。微批处理执行方法仍然存在一些问题,特别是在大范围内的性能问题。最近,由于应用程序要求开发一种连续处理模式,Spark受到了刺激。2.3版的实验性版本只支持简单的类地图操作。
在最近的Spark+AI峰会上的更新之后,连续处理似乎已经发展成为一个与Flink的流处理模型非常相似的执行引擎。然而,如上图所示,主要功能仍在继续发展。它们的性能如何,以及将来如何与Spark原来的批处理执行引擎集成,还有待观察。
(原文王海涛王海涛)
本文是阿里巴巴Flink系列的一部分。
首席点评:
这边文章原文有些都针对的是Spark 2.3 ,目前Spark 3.0已经发布了。文章内容虽然不是最新的,但是对于了解发展变化还是有帮助的。