随着Spark的逐渐成熟完善, 越来越多的可配置参数被添加到Spark中来, 在Spark的官方文档http://spark.apache.org/docs/latest/configuration.html 中提供了这些可配置参数中相当大一部分的说明.

但是文档的更新总是落后于代码的开发的, 还有一些配置参数没有来得及被添加到这个文档中, 最重要的是在这个文档中,对于许多的参数也只能简单的介绍它所代表的内容的字面含义, 如果没有一定的实践基础或者对其背后原理的理解, 往往无法真正理解该如何针对具体应用场合进行合理配置。

本文试图通过阐述这其中部分参数的工作原理和配置思路, 和大家一起探讨一下如何根据实际场合对Spark进行配置优化。需要注意的是,理论上,没有绝对正确的配置(否则也就不需要对应的配置参数了,Spark框架内部直接写死就好了),所以请结合自己的实际情况,辩证的看下面的内容。

由于本文主要针对和性能相关的一些配置参数进行阐述,所以基本不会覆盖其它和性能没有太多关系的配置参数。

由于篇幅较长,所以在这里分篇组织,如果要看最新完整的网页版内容,可以戳这里:http://spark-config.readthedocs.org/,主要是便于更新内容

Shuffle 相关

Shuffle操作大概是对Spark性能影响最大的步骤之一(因为可能涉及到排序,磁盘IO,网络IO等众多CPU或IO密集的操作),这也是为什么在Spark 1.1的代码中对整个Shuffle框架代码进行了重构,将Shuffle相关读写操作抽象封装到Pluggable的Shuffle Manager中,便于试验和实现不同的Shuffle功能模块。例如为了解决Hash Based的Shuffle Manager在文件读写效率方面的问题而实现的Sort Base的Shuffle Manager。

spark.shuffle.manager

用来配置所使用的Shuffle Manager,目前可选的Shuffle Manager包括默认的org.apache.spark.shuffle.sort.HashShuffleManager(配置参数值为hash)和新的org.apache.spark.shuffle.sort.SortShuffleManager(配置参数值为sort)。

这两个ShuffleManager如何选择呢,首先需要了解他们在实现方式上的区别。

HashShuffleManager,故名思义也就是在Shuffle的过程中写数据时不做排序操作,只是将数据根据Hash的结果,将各个Reduce分区的数据写到各自的磁盘文件中。带来的问题就是如果Reduce分区的数量比较大的话,将会产生大量的磁盘文件。如果文件数量特别巨大,对文件读写的性能会带来比较大的影响,此外由于同时打开的文件句柄数量众多,序列化,以及压缩等操作需要分配的临时内存空间也可能会迅速膨胀到无法接受的地步,对内存的使用和GC带来很大的压力,在Executor内存比较小的情况下尤为突出,例如Spark on Yarn模式。

SortShuffleManager,是1.1版本之后实现的一个试验性(也就是一些功能和接口还在开发演变中)的ShuffleManager,它在写入分区数据的时候,首先会根据实际情况对数据采用不同的方式进行排序操作,底线是至少按照Reduce分区Partition进行排序,这样来至于同一个Map任务Shuffle到不同的Reduce分区中去的所有数据都可以写入到同一个外部磁盘文件中去,用简单的Offset标志不同Reduce分区的数据在这个文件中的偏移量。这样一个Map任务就只需要生成一个shuffle文件,从而避免了上述HashShuffleManager可能遇到的文件数量巨大的问题

两者的性能比较,取决于内存,排序,文件操作等因素的综合影响。

对于不需要进行排序的Shuffle操作来说,如repartition等,如果文件数量不是特别巨大,HashShuffleManager面临的内存问题不大,而SortShuffleManager需要额外的根据Partition进行排序,显然HashShuffleManager的效率会更高。

而对于本来就需要在Map端进行排序的Shuffle操作来说,如ReduceByKey等,使用HashShuffleManager虽然在写数据时不排序,但在其它的步骤中仍然需要排序,而SortShuffleManager则可以将写数据和排序两个工作合并在一起执行,因此即使不考虑HashShuffleManager的内存使用问题,SortShuffleManager依旧可能更快。

spark.shuffle.sort.bypassMergeThreshold

这个参数仅适用于SortShuffleManager,如前所述,SortShuffleManager在处理不需要排序的Shuffle操作时,由于排序带来性能的下降。这个参数决定了在这种情况下,当Reduce分区的数量小于多少的时候,在SortShuffleManager内部不使用Merge Sort的方式处理数据,而是与Hash Shuffle类似,直接将分区文件写入单独的文件,不同的是,在最后一步还是会将这些文件合并成一个单独的文件。这样通过去除Sort步骤来加快处理速度,代价是需要并发打开多个文件,所以内存消耗量增加,本质上是相对HashShuffleMananger一个折衷方案。 这个参数的默认值是200个分区,如果内存GC问题严重,可以降低这个值。

spark.shuffle.consolidateFiles

这个配置参数仅适用于HashShuffleMananger的实现,同样是为了解决生成过多文件的问题,采用的方式是在不同批次运行的Map任务之间重用Shuffle输出文件,也就是说合并的是不同批次的Map任务的输出数据,但是每个Map任务所需要的文件还是取决于Reduce分区的数量,因此,它并不减少同时打开的输出文件的数量,因此对内存使用量的减少并没有帮助。只是HashShuffleManager里的一个折中的解决方案。

需要注意的是,这部分的代码实现尽管原理上说很简单,但是涉及到底层具体的文件系统的实现和限制等因素,例如在并发访问等方面,需要处理的细节很多,因此一直存在着这样那样的bug或者问题,导致在例如EXT3上使用时,特定情况下性能反而可能下降,因此从Spark 0.8的代码开始,一直到Spark 1.1的代码为止也还没有被标志为Stable,不是默认采用的方式。此外因为并不减少同时打开的输出文件的数量,因此对性能具体能带来多大的改善也取决于具体的文件数量的情况。所以即使你面临着Shuffle文件数量巨大的问题,这个配置参数是否使用,在什么版本中可以使用,也最好还是实际测试以后再决定。

spark.shuffle.spill

shuffle的过程中,如果涉及到排序,聚合等操作,势必会需要在内存中维护一些数据结构,进而占用额外的内存。如果内存不够用怎么办,那只有两条路可以走,一就是out of memory 出错了,二就是将部分数据临时写到外部存储设备中去,最后再合并到最终的Shuffle输出文件中去。

这里spark.shuffle.spill 决定是否Spill到外部存储设备(默认打开),如果你的内存足够使用,或者数据集足够小,当然也就不需要Spill,毕竟Spill带来了额外的磁盘操作。

spark.shuffle.memoryFraction/ spark.shuffle.safetyFraction

在启用Spill的情况下,spark.shuffle.memoryFraction(1.1后默认为0.2)决定了当Shuffle过程中使用的内存达到总内存多少比例的时候开始Spill。

通过spark.shuffle.memoryFraction可以调整Spill的触发条件,即Shuffle占用内存的大小,进而调整Spill的频率和GC的行为。总的来说,如果Spill太过频繁,可以适当增加spark.shuffle.memoryFraction的大小,增加用于Shuffle的内存,减少Spill的次数。当然这样一来为了避免内存溢出,对应的可能需要减少RDD cache占用的内存,即减小spark.storage.memoryFraction的值,这样RDD cache的容量减少,有可能带来性能影响,因此需要综合考虑。

由于Shuffle数据的大小是估算出来的,一来为了降低开销,并不是每增加一个数据项都完整的估算一次,二来估算也会有误差,所以实际暂用的内存可能比估算值要大,这里spark.shuffle.safetyFraction(默认为0.8)用来作为一个保险系数,降低实际Shuffle使用的内存阀值,增加一定的缓冲,降低实际内存占用超过用户配置值的概率。

spark.shuffle.spill.compress/ spark.shuffle.compress

这两个配置参数都是用来设置Shuffle过程中是否使用压缩算法对Shuffle数据进行压缩,前者针对Spill的中间数据,后者针对最终的shuffle输出文件,默认都是True

理论上说,spark.shuffle.compress设置为True通常都是合理的,因为如果使用千兆以下的网卡,网络带宽往往最容易成为瓶颈。此外,目前的Spark任务调度实现中,以Shuffle划分Stage,下一个Stage的任务是要等待上一个Stage的任务全部完成以后才能开始执行,所以shuffle数据的传输和CPU计算任务之间通常不会重叠,这样Shuffle数据传输量的大小和所需的时间就直接影响到了整个任务的完成速度。但是压缩也是要消耗大量的CPU资源的,所以打开压缩选项会增加Map任务的执行时间,因此如果在CPU负载的影响远大于磁盘和网络带宽的影响的场合下,也可能将spark.shuffle.compress 设置为False才是最佳的方案

对于spark.shuffle.spill.compress而言,情况类似,但是spill数据不会被发送到网络中,仅仅是临时写入本地磁盘,而且在一个任务中同时需要执行压缩和解压缩两个步骤,所以对CPU负载的影响会更大一些,而磁盘带宽(如果标配12HDD的话)可能往往不会成为Spark应用的主要问题,所以这个参数相对而言,或许更有机会需要设置为False。

总之,Shuffle过程中数据是否应该压缩,取决于CPU/DISK/NETWORK的实际能力和负载,应该综合考虑。

Spark 性能相关参数配置详解-shuffle篇的更多相关文章

  1. Spark 性能相关参数配置详解-任务调度篇

    随着Spark的逐渐成熟完善, 越来越多的可配置参数被添加到Spark中来, 本文试图通过阐述这其中部分参数的工作原理和配置思路, 和大家一起探讨一下如何根据实际场合对Spark进行配置优化. 由于篇 ...

  2. Spark 性能相关参数配置详解-压缩与序列化篇

    随着Spark的逐渐成熟完善, 越来越多的可配置参数被添加到Spark中来, 本文试图通过阐述这其中部分参数的工作原理和配置思路, 和大家一起探讨一下如何根据实际场合对Spark进行配置优化. 由于篇 ...

  3. Spark 性能相关参数配置详解-Storage篇

    随着Spark的逐渐成熟完善, 越来越多的可配置参数被添加到Spark中来, 本文试图通过阐述这其中部分参数的工作原理和配置思路, 和大家一起探讨一下如何根据实际场合对Spark进行配置优化. 由于篇 ...

  4. druid 参数配置详解

    druid 参数配置详解 */--> druid 参数配置详解 Table of Contents 1. 初始化连接 2. 参数配置及说明 3. 注意事项 3.1. 底层连接 3.2. 空闲检查 ...

  5. Nginx.conf参数配置详解

    Nginx的配置文件nginx.conf配置详解如下: user nginx nginx; #Nginx用户及组:用户 组.window下不指定 worker_processes 8; #工作进程:数 ...

  6. logback 常用参数配置详解

    logback 常用配置详解(二) <appender> <appender>: <appender>是<configuration>的子节点,是负责写 ...

  7. HDFS之三:hdfs参数配置详解

    1.hdfs-site.xml 参数配置 – dfs.name.dir – NameNode 元数据存放位置 – 默认值:使用core-site.xml中的hadoop.tmp.dir/dfs/nam ...

  8. KingbaseES V8R6集群同步模式synchronous参数配置详解

    如下图所示: 集群数据同步原理说明: synchronous参数配置测试: 集群节点信息: ID | Name | Role | Status | Upstream | repmgrd | PID | ...

  9. JVM参数配置详解-包含JDK1.8

    堆大小设置    JVM 中最大堆大小有三方面限制:相关操作系统的数据模型(32-bt还是64-bit)限制:系统的可用虚拟内存限制:系统的可用物理内存限制.32位系统下,一般限制在1.5G~2G:6 ...

随机推荐

  1. cocos2d js jsb XMLHttpRequest 中文乱码

    1.首先讲下怎样使用XMLHttpRequest 下面所说的是在cocos2d-x 2.2.2 或者 2.3 版本号中. 首先要明确cocos2d js事实上分两个版本号,一个是html5的版本号,另 ...

  2. cocos2d-x 3.2 关闭按钮点击立马销毁自己报错

    cocos2d-x 3.2 Button点击事件里调用移除当前层报错 http://www.th7.cn/program/ios/201408/271227.shtml 诡异的错误,点击关闭按钮,居然 ...

  3. 嵌入式视频采集编程思路(Video 4 Linux)-转

    转自:http://zyg0227.blog.51cto.com/1043164/271954 1.  linux 内核有video for linux简称V4L.V4L是Linux影像系统与嵌入式影 ...

  4. promise的学习心得记录

    这里只讲promise,和async的使用方法,不会讲他们的原理. Promise 是异步编程的一种解决方案,可以用于取代传统的回调函数,该变那些函数层层嵌套调用的尴尬局面. 1)promise 基本 ...

  5. ShowDialog窗体的return问题

    最近的一个项目里,打开新窗口用到了ShowDialog()这种方式,发现在新窗口做保存操作的时候,保存按钮事件下的程序执行完(无论有没有return)都会关闭子窗口. 网上查了一下,发现大家说的方法在 ...

  6. python-redis-pipe文件

    redis导入数据比较头疼的事情,涉及几千万,导入还是很耗时,通过生成pipe文件的方式比较快捷. python3.6.1版本 在linux环境下运行 with open("data1&qu ...

  7. Glide源码解析

    基本使用方法: Glide.with(this) .asDrawable() .load("http://i6.topit.me/6/5d/45/1131907198420455d6o.jp ...

  8. PdfPCell对齐方式,边框,边框颜色的使用 (转)

    原文:http://www.cnblogs.com/LifelongLearning/archive/2011/06/22/2086802.html PdfPTable和PdfPCell对象,我们可以 ...

  9. UI“三重天”之实践Uiautomator1

    说起来Uiautomator也有一年没碰过了.借此来回顾.总结一下. 也是阅读<精通APP自动化测试>一书.实践出真知的一个框架.编写了部分移动端UI自动化脚本.后续再深入学习. 虽然现在 ...

  10. Web项目中定时任务无法绑定SessionFactory的问题解决

    正常我们在web开发中,由于需要在页面上或者脱离事务时使用到懒加载对应的对象,一般都采用Open Session In View模式.   Open Session In View   OpenSes ...