自两年前Spark 1.0发布以来,我们收到了很多意见,或褒或贬;而Spark 2.0正是基于我们过去两年来获得的经验总结来构建的,它着重加强了用户喜爱的功能,改善了大家不满的地方。本文总结了Spark2.0的三个主要改进方向:更简单、更快速、更智能
我们欣喜地宣布,从今天起大家可以在Databricks下载Apache Spark 2.0的技术预览版(社区版)了,该数据包使用upstream branch-2.0构建,使用起来非常简单,只要在启动集群时选择“2.0(branch preview)”版本就可以了。
在Databricks创建一个新Apache Spark 2.0技术预览版集群的工作流程截图
由于Apache Spark 2.0的最终发布版尚需几周才能出炉,本技术预览版旨在让大家提前预览一下新版的功能,一方面满足大家的好奇心,一方面也便于我们在发布最终版前多收集一些用户反馈与bug报告。
现在我们来看看新的变化吧。
Spark 2.0:更简单、更快速、更智能
更简单:SQL与简化的APISpark让我们引以为豪的一点就是所创建的API简单、直观、便于使用,Spark 2.0延续了这一传统,并在两个方面凸显了优势:1)标准的SQL支持;2)统一数据框(DataFrame)/数据集API。
在SQL方面,我们已经对Spark的SQL功能做了重大拓展,引入了新的ANSI SQL解析器,并支持子查询功能。 Spark 2.0可以运行所有99个TPC-DS查询(需求SQL:2003中的很多功能支持)。由于SQL是Spark应用所使用的主要接口之一,对SQL功能的拓展大幅削减了将遗留应用移植到Spark时所需的工作。
在编程API方面,我们简化了API:
l 在Scala/Java中统一了DataFrames与Dataset:从Spark 2.0开始,DataFrames只是行(row)数据集的typealias了。无论是映射、筛选、groupByKey之类的类型方法,还是select、groupBy之类的无类型方法都可用于Dataset的类。此外,这个新加入的Dataset接口是用作结构化数据流(Structured Streaming)的抽象,由于Python和R语言中的编译时类型安全(compile-time type-safety)不属于语言特性,数据集的概念无法应用于这些语言API中。而DataFrame仍是主要的编程抽象,在这些语言中类似于单节点DataFrames的概念,可以查看数据集API手册做些了解。
l SparkSession:这是一个新入口,取代了原本的SQLContext与HiveContext。对于DataFrame API的用户来说,Spark常见的混乱源头来自于使用哪个“context”。现在你可以使用SparkSession了,它作为单个入口可以兼容两者。注意原本的SQLContext与HiveContext仍然保留,以支持向下兼容。
l 更简单、性能更佳的Accumulator API:我们设计了一个新的Accumulator API,不但在类型层次上更简洁,同时还专门支持基本类型。原本的Accumulator API已不再使用,但为了向下兼容仍然保留。
l 基 于DataFrame的机器学习API将作为主ML API出现:在Spark 2.0中,spark.ml包及其“管道”API会作为机器学习的主要API出现,尽管原本的spark.mllib包仍然保留,但以后的开发重点会集中在基于DataFrame的API上。
l 机器学习管道持久化:现在用户可以保留与载入机器学习的管道与模型了,Spark对所有语言提供支持。
l R语言的分布式算法:增加对广义线性模型(GLM)、朴素贝叶斯算法(NB算法)、存活回归分析(Survival Regression)与聚类算法(K-Means)的支持。
速度更快:用Spark作为编译器根据我们2015年对Spark的调查,91%的用户认为对Spark来说,性能是最为重要的。因此,性能优化一直是我们在开发Spark时所考虑的重点。在开始Spark 2.0的规划前,我们思考过这个问题: Spark的速度已经很快了,但能否突破极限,让Spark达到原本速度的10倍呢?
带着这个问题,我们切实考虑了在构建Spark物理执行层面时的方式。如果深入调查现代的数据引擎,比如Spark或者其他MPP数据库,我们会发现:CPU循环大多都做了无用功,比如执行虚拟函数调用,或者向CPU缓存或内存读取/写入中间数据;通过减少CPU循环中的浪费来优化性能,一直是我们在现代编译器上长时间以来的工作重点。
Spark 2.0搭载了第二代Tungsten引擎,该引擎是根据现代编译器与MPP数据库的理念来构建的,它将这些理念用于数据处理中,其主要思想就是在运行时使用优化后的字节码,将整体查询合成为单个函数,不再使用虚拟函数调用,而是利用CPU来注册中间数据。我们将这一技术称为“whole-stage code generation”。
在测试、对比Spark 1.6与Spark 2.0时,我们列出了在单核中处理单行数据所花费的时间(以十亿分之一秒为单位),下面的表格证明了新一代Tungsten引擎的强大。Spark 1.6包含代码生成技术(code generation)的使用,这一技术如今在一些顶尖的商业数据库中也有运用,正如我们看到的那样,使用了新whole-stage code generation技术后,速度比之前快了一个数量级。
我们在单台机器上对10亿记录执行了aggregations和joins操作。
每行耗费(单线程)
这个新的引擎在执行端对端查询时是如何运作的?我们使用TPC-DS查询做了些初步分析,以对比Spark 1.6与Spark 2.0:
除此之外,为了改进Catalyst optimizer优化器对诸如nullability propagation之类常见查询的效果,我们还做了许多工作;另外还改进了矢量化Parquet解码器,新解码器的吞吐量增加了三倍。
更智能:结构化数据流作为首个尝试统一批处理与流处理计算的工具,Spark Streaming一直是大数据处理的领导者。首个流处理API叫做DStream,在Spark 0.7中初次引入,它为开发者提供了一些很强大的属性,包括:只有一次语义,大规模容错,以及高吞吐。
然而,在处理了数百个真实世界的Spark Streaming部署之后,我们发现需要在真实世界做决策的应用经常需要不止一个流处理引擎。他们需要深度整合批处理堆栈与流处理堆栈,整合内部存储系统,并且要有处理业务逻辑变更的能力。因此,各大公司需要不止一个流处理引擎,并且需要能让他们开发端对端“持续化应用”的全栈系统。
有一种看法是将所有一切当作流数据,也就是说采用单一的编程模型来整合批数据与流数据。
在这种单一的模型中,有大量的问题出现。首先,在接收到数据的第一时间进行处理非常困难,也很有局限性。其次,不同的数据分布、变动的业务逻辑与数据延迟都增加了实际操作的挑战性。再次,大多现有系统比如MySQL或者Amazon S3都不支持流处理,大多现有的机器学习算法在streaming设置中都不起作用。
Spark 2.0的结构化Streaming API是处理流数据的全新方式,源于“在流数据中计算答案的最简单方式就是不管它们是不是流数据”。这种实现来源于经验:已经了解如何编写静态数据集(即批数据)的程序员使用Spark强大的DataFrame/Dataset API所总结出来的经验。结构化数据流的愿景就是利用Catalyst优化器找出:何时可以将静态程序转化为动态、无限数据的增量执行(即流处理)。当遇到结构化数据,比如离散表或者infinite表格时,就可以简单地运用流处理的方式。
作为这一愿景实现的第一步,Spark 2.0搭载了初始版本的结构化流处理API,这是一个附在DataFrame/Dataset API上的(超小)扩展包。统一之后,对现有的Spark用户来说使用起来非常简单,他们能够利用在Spark 批处理API方面的知识来回答实时的新问题。这里关键的功能包括:支持基于事件时间的处理,无序/延迟数据,sessionization以及非流式数据源与Sink的紧密集成。
Streaming很明显是一个非常广泛的话题,因此想要了解Spark 2.0中结构化流处理的更多信息,请关注本博客,后续还有Spark 2.0发布版的一些细节内容与近期的计划。
结论Spark的用户最初使用Spark是因为它的易用性与高性能。Spark 2.0在这些方面达到了之前的两倍,并增加了对多种工作负载的支持。我们希望我们的努力能令大家满意,并希望大家积极反馈。
当然,在Apache Spark 2.0最终版发布之前,我们不建议完全将生产环境的工作迁移到这个预览版上。新发布包在Databricks上就有下载(社区版),在最近几天内我们会陆续向所有Databricks客户发布。
原文链接:https://databricks.com/blog/2016/05/11/spark-2-0-technical-preview-easier-faster-and-smarter.html
作者:Reynold Xin
翻译:孙薇