stone

通过测试进行Spark调优
这是阅读《Spark Parameter Tunning via Trial-and-Error》的阅读笔记。文中...
扫描右侧二维码阅读全文
27
2016/12

通过测试进行Spark调优

这是阅读《Spark Parameter Tunning via Trial-and-Error》的阅读笔记。

文中主要是通过分析12个参数对三个实验的效果,然后得到一个调优的测试顺序和方法,基本上不涉及Spark运行的原理,只通过比较两个不同的参数的效果选择一个较好的参数,然后继续比较下一组数据。

这个调优的方法条理比较清晰,值得学习!

正文

Spark能够调优的参数有大概150多个,按照其影响的结果可以分为下面几类:

Application Properties,Execution Behavior,Networking,Spark UI,Security,Encryption,Spark Streaming and Spark R,Runtime Environment,Shuffle Behavior,Compression and Serialization,Memory Management,Scheduling,Dynamic Allocation

影响性能的一个基本因素是分配给Excutor的核心数,这直接影响一个应用的并行能力,并且应该根据应用的不同而进行考虑。另一个影响较大的因素是分区的策略。对于一些计算密集型应用(cpu-intensive application),理想的情况是一个核心负责一个分区,而对于需要经常进行数据混洗的应用,应该增加分区的数量,从而优化其性能。最后还提到了一点就是底层的文件系统的性能对应用的性能也有很大的影响。

另文中主要研究的参数有下面的12个👇:

👉 spark.reducer.maxSizeInFlight: shuffle过程分配的内存大小,默认为0.2,其大小会影响其他内存的分配,需要根据Spark应用的实际情况进行微调

👉 spark.shuffle.compress: shuffle过程中数据传输压缩选项,需要衡量压缩和传输的损耗

👉 spark.shuffle.file.buffer: 和maxSizeInFlight相似

👉 spark.reducer.manager: 有三个选项:sort,hash,tungsten-sort,三种方法各有优势,目前不是太清楚其原理❓

👉 spark.io.compression.codec: 提供三个选项: snappy,lz4,lzf,需要根据不同应用进行设置❓

👉 spark.shuffle.io.preferDirectBufs: ❓

👉 spark.rdd.compress: 压缩选项,需要衡量计算,传输和存储的关系

👉 spark.serializer: KryoSerializer,性能更好,但是配置麻烦

👉 spark.shuffle.memoryFraction: 运行内存

👉 spark.storage.memoryFraction:cache使用的内存大小

👉 spark.shuffle.consolidateFiles: shuffle过程中合并文件的选项,影响shuffle的性能

👉 spark.shuffle.spill.compress: shuffler时传输的压缩选项外文中还提到了另外的一些方面,如序列化的效率,内存的分配,分区的数量,失败与竞争性任务(failed or straggling tasks)的策略,GC的性能(文中不作考虑)等等。

文中采用了三个实验进行分析:

实验使用的机器为20台16核服务器,平均每个核心分配的内存为1.5GB,Spark版本为1.5.2

sort-by-key

提供大概十亿的key-value数据,每个key和value大约10~90bytes,key和value中有一百万个不同的值。数据两大约为200MB~2G左右,partition数为640

个人分析: sort-by-key是对同一个key的数据进行排序的操作,会先生成一个shufflemap将同一key的数据放到一个paritiion上,从而避免大量的shuffle过程,对并行度要较高,对运行内存要求不高,同时含有大量的shuffle操作,进行网络传输,对shuffle性能要求较高,可能会出现一个task需要从20台机器进行拉去,估计需要拉取八百万次左右,大约估计平均每个task分到的数据量不足1M,所以计算性能对结果影响较小,主要落在网络传输。

shuffling

原始数据大约有400G数据进行shuffle操作,这个实验中要求Excutor的内存约为400G,所以不可避免地需要向硬盘写入硬盘数据

个人分析: 因为Executor的运行内存肯定是不足的,在进行shuffle操作的时候会有大量的硬盘IO操作,同时也有大量的网络传输,因为数据量太大了,所以可以假设硬盘IO和网络传输所有的时间都很大

k-means

k-means 算法,输入数据大约为100M和200M的100维数据,有10个中心点,迭代10次左右

个人分析:这次使用的数据不大,主要操作在于CPU计算,影响较大的操作可能是运行内存等等和计算相关的参数,和shuffle传输也有一些关系

!

下面是实验结果的分析:

1. sort-by-key

!

作者首先测试了spark.serializer=KryoSerializer,性能有约25%的提升,为150秒左右,然后以这个数据作为基准,和其他数据进行比较,在比较时,只有一个参数不同。

  • spark.shuffle.manager: hash和tungsten-sort性能相似,分别为127秒和131秒
  • spark.shuffle.memoryFraction和spark.storage.memory: 理论上对于shuffle-intensive应用会有较大的提升,但是实际上提升不大,为139秒,而另一组则是程序奔溃,没有数据

个人分析: shuffle过程中如果shuffle使用的内存不足,就会将拉取的数据进行合并,然后放到硬盘中,但是这次实验中shuffle的内存分别为307M(0.2)和614(0.4),数据量不大,shuffle过程基本都在内存中完成,所以效果不大

  • spark.reducer.maxSizeInFlight:效果也不大

个人分析: 其他很多参数效果都不是很明显,估计问题和上面相似,下面就不列出来了

  • spark.shuffle.compress: 在不进行压缩的情况下,性能下降了100%

个人分析: 和上面的分析相似,这个实验的主要操作是shuffle的拉取操作,而在拉去过程中cpu处理性能还是比较充足的,所以影响传输数据量和速度的参数会有很大的影响。

shuffle实验

  • spark.serializer=KryoSerializer:和之前一样,下面所有的参数都是以这个作为基准,效果有约10%的提升,基准时间为815秒
  • spark.shuffle.manager: 使用Hash的情况下时间慢了200秒,而使用Tungsten-sort则快了90秒
  • shuffle.memoryFraction,storage.momeryFraction:基本作用不大,运行还慢了
  • spark.reducer.maxSizeInFlight,spark.shuffle.file.buffer:基本左右不大,可能是因为数据量太大了,但是如果这个值过小,会增加硬盘读写次数
  • spark.io.compress.codec:lz4和lzf都让效率下降了,主要问题可能还是数据太大了
  • 剩下的其他参数效果都不是很明显,不作描述

K-means实验

  • spark.serializer:KryoSerializer的优化比较小
  • 其他的参数基本性能替身提升不足10%,作者也没有作较多的分析

个人分析: 这部份主要应该优化如paritition数量,task数量等影响集群利用率的参数中


最后文中根据之前的结果总结了一个调优的方法:

每一个分支选择都是一个测试,通过运行测试用例来选择使用哪一个参数,然后子节点继承上面的配置,继续进行测试,基本上运行10次左右就能找到一个较好的优化配置

在最后作者对上面的几个实验使用上述方法进行测试,最后性能都得到大幅度提升,尤其是之前效果一直不太明显的k-means,性能提高90%+,具体原理不明

Last modification:September 7th, 2018 at 08:21 pm
If you think my article is useful to you, please feel free to appreciate

Leave a Comment