一、技术背景

Spark1.x版本中执行SQL语句,使用的是一种最经典,最流行的查询求职策略,该策略主要基于 Volcano Iterator Model(火山迭代模型)。一个查询会包含多个Operator,每个Operator都会实现一个接口,提供一个next()方法,该方法返回Operator Tree的下一个Operator,能够让查询引擎组装任意Operator,而不需要去考虑每个Operator具体的处理逻辑,所以Volcano Iterator Model 才成为了20年中SQL执行引擎最流行的一种标准。

比如如下SQL语句:

select count(*) from employees where salary == 1000

使用Java代码手写实现的SQL功能的代码如下

int count = 0;
for(emp : employees){
if(emp == 1000){
count += 1;
}
}

有人实验了Volcano Iterator Model 方式与直接手写Java代码实现的方式,直接手写Java代码是专门为了实现某个指定的功能而编写的,不具有良好的组装性和扩展性,这两种方式进行了性能的对比结果如下图。

可以看到直接手写Java代码实现某一特定功能的性能比Volcano模型的性能高出了一个数量级,主要的原因有三点:

1. 避免了虚函数调用(Virtual Function Dispatch),Volcano Iterator Model至少需要调用一次next()获取下一个Operator,在操作系统层面会被编译为Virtual Function Dispatch,会执行多个CPU指令,并且速度慢。而直接编写的Java代码中没有任何函数调用逻辑。

2. 使用CPU寄存器存取中间数据 。 Volcano Iterator Model将数据交给下一个Operator时,都需要将数据写入内存缓冲,但是在手写代码中,JVM JIT编译器会将这些数据写入CPU寄存器,CPU直接从寄存器中读写数据比在内存缓冲中读写数据的性能要高一个数量级。

3.编译器Loop Unrolling。手写代码针对某特定功能使用简单循环,而现代的编译器可以自动的对简单循环进行Unrolling,生成单指令多数据流(SIMD),在每次CPU指令执行时处理多条数据。而这些优化特点无法在Volcano Iterator Model复杂的函数调用场景中施展。

二、Whole-stage code generation

1. Spark性能调优思路

在以上论述的技术背景下,如果要对Spark进行性能优化,应该避免使用Volcano模型,在运行时动态生成代码。由此,Spark2.x版本中,基于Tungsten引擎的Whole-stage code generation 技术应运而生。SQL语句编译后的Operator-Tree中,每个Operator不再执行逻辑,而是通过全流式代码生成技术在运行时动态生成代码,并尽量将所有的操作打包到一个函数中。如果是简单查询,Spark会尽量生成一个Stage,如果是复杂的查询,就可能会生成多个Stage。

2. Spark2.x的SQL执行计划

Spark提供了一个explain( )方法来查询SQL的执行计划。

例子:

准备工作:通过saprk读取HDFS上的员工表信息(emp.csv),执行操作如下:

scala> case class Emp(eno:Int,ename:String,job:String,mgr:String,hiredate:String,sal:Int,comm:String,deptno:Int)
defined class Emp scala> val lines = sc.textFile("hdfs://bigdata11:9000/input/emp.csv").map(_.split(","))
lines: org.apache.spark.rdd.RDD[Array[String]] = MapPartitionsRDD[9] at map at <console>:24 scala> val allEmp = lines.map(x => Emp(x(0).toInt,x(1),x(2),x(3),x(4),x(5).toInt,x(6),x(7).toInt))
allEmp: org.apache.spark.rdd.RDD[Emp] = MapPartitionsRDD[10] at map at <console>:28 scala> val empDF = allEmp.toDF
empDF: org.apache.spark.sql.DataFrame = [eno: int, ename: string ... 6 more fields]

  

查看执行计划:通过explain()方法查看执行计划。前面带*号的步骤就是通过whole-stage code generation生成的。

三、总结

从以上分析可以看出Spark2.x引入的whole-stage code generation技术,使Spark2.x的性能比Spark1.x的性能有所提高。但并不是所有的操作都能够大幅提升性能,whole-stage code generation技术是从CPU密集操作的方面进行性能调优,对IO密集操作的层面是无法提高效率的,比如Shuffle中产生的读写磁盘操作是无法通过该技术提升性能的,Spark未来版本的更新还需要从IO密集操作层面进行性能调优。

【Spark】Spark性能优化之Whole-stage code generation的更多相关文章

  1. SparkSQL的一些用法建议和Spark的性能优化

    1.写在前面 Spark是专为大规模数据处理而设计的快速通用的计算引擎,在计算能力上优于MapReduce,被誉为第二代大数据计算框架引擎.Spark采用的是内存计算方式.Spark的四大核心是Spa ...

  2. [看图说话] 基于Spark UI性能优化与调试——初级篇

    Spark有几种部署的模式,单机版.集群版等等,平时单机版在数据量不大的时候可以跟传统的java程序一样进行断电调试.但是在集群上调试就比较麻烦了...远程断点不太方便,只能通过Log的形式,进行分析 ...

  3. Spark实践 -- 性能优化基础

    性能调优相关的原理讲解.经验总结: 掌握一整套Spark企业级性能调优解决方案:而不只是简单的一些性能调优技巧. 针对写好的spark作业,实施一整套数据倾斜解决方案:实际经验中积累的数据倾斜现象的表 ...

  4. spark mongo 性能优化

    性能优化事项 http://www.mongoing.com/wp-content/uploads/2016/08/MDBSH2016/TJ_MongoDB+Spark.pdf MongoDB + S ...

  5. Spark SQL 性能优化再进一步:CBO 基于代价的优化

    摘要: 本文将介绍 CBO,它充分考虑了数据本身的特点(如大小.分布)以及操作算子的特点(中间结果集的分布及大小)及代价,从而更好的选择执行代价最小的物理执行计划,即 SparkPlan. Spark ...

  6. Spark Streaming性能优化: 如何在生产环境下应对流数据峰值巨变

    1.为什么引入Backpressure 默认情况下,Spark Streaming通过Receiver以生产者生产数据的速率接收数据,计算过程中会出现batch processing time > ...

  7. Spark Streaming性能优化系列-怎样获得和持续使用足够的集群计算资源?

    一:数据峰值的巨大影响 1. 数据确实不稳定,比如晚上的时候訪问流量特别大 2. 在处理的时候比如GC的时候耽误时间会产生delay延迟 二:Backpressure:数据的反压机制 基本思想:依据上 ...

  8. 《Spark大数据处理:技术、应用与性能优化 》

    基本信息 作者: 高彦杰 丛书名:大数据技术丛书 出版社:机械工业出版社 ISBN:9787111483861 上架时间:2014-11-5 出版日期:2014 年11月 开本:16开 页码:255 ...

  9. 《Spark大数据处理:技术、应用与性能优化》【PDF】 下载

    内容简介 <Spark大数据处理:技术.应用与性能优化>根据最新技术版本,系统.全面.详细讲解Spark的各项功能使用.原理机制.技术细节.应用方法.性能优化,以及BDAS生态系统的相关技 ...

随机推荐

  1. springmvc/springboot处理前台字符串日期自动转换成后台date类型的三种办法

    参考https://blog.csdn.net/eumenides_/article/details/79033505 补充一个:Formatter也可以实现.

  2. androidtab

    https://github.com/H07000223/FlycoTabLayout tensorflow https://github.com/topics/tensorflow-examples ...

  3. Thinkphp中在本地测试很好,在服务器上出错,有可能是因为debug缓存的问题

    define('APP_DEBUG',false); 这个设置从true改为false后,一定要清空缓存,否则会出错.

  4. 如果Android的jar包导入错误,怎么修改呢?

    如果jar包导入错误,怎么修改呢? 右键工程---->properties---->Java Build Path --->Libraries-->选择android-supp ...

  5. windows10 如何关闭快速关机功能电源选项

    点击右下角的电池 -> power and sleep setting -> choose what the power buttons do -> change settings ...

  6. hiredis

    hiredis是redis开源库对外发布的客户端API包. 当redis-server配置启动后,可以通过hiredis操作redis资源. 主要分为: strings.hash.lists.sets ...

  7. Python 冒泡排序法分析

    冒泡排序法 def maopao(): array = [2,1,3,6,5,4] #确定一组需要排序的数值列表 for i in range(len(array)-1): #大循环次数=列表长度,但 ...

  8. 记两个std接口equal_range,set_difference

    1.equal_range equal_range是C++ STL中的一种二分查找的算法,试图在已排序的[first,last)中寻找value,它返回一对迭代器i和j,其中i是在不破坏次序的前提下, ...

  9. (fields.E130) DecimalFields must define a 'decimal_places' attribute.

    DecimalField类型:固定精度的十进制数,一般用来存金额相关的数据.额外的参数包括DecimalField.max_digits(整个数字的长度)和DecimalField.decimal_p ...

  10. BZOJ2756:[SCOI2012]奇怪的游戏(最大流,二分)

    Description Blinker最近喜欢上一个奇怪的游戏. 这个游戏在一个 N*M 的棋盘上玩,每个格子有一个数.每次 Blinker 会选择两个相邻 的格子,并使这两个数都加上 1. 现在 B ...