Spark中shuffle过程的优化

shuffle调优



前言

Spark的shuffle要比MapReduce的shuffle快很多(原因是:MapReduce的shuffle数据是要落盘的,而Spark是基于内存的计算),并且Spark中只有遇到行动算子的时候才会有shuffle过程。

一、Spark中的shuffle是什么?

Shuffle描述着数据从map task输出到reduce task输入的这段过程。shuffle是连接Map和Reduce之间的桥梁,Map的输出要用到Reduce中必须经过shuffle这个环节,shuffle的性能高低直接影响了整个程序的性能和吞吐量。

二、shuffle调优

1.调整map端缓冲区的大小

在 Spark 任务运行过程中,如果 shuffle 的 map 端处理的数据量比较大,但是 map 端缓
冲的大小是固定的,可能会出现 map 端缓冲数据频繁 spill 溢写到磁盘文件中的情况,使得
性能非常低下,通过调节 map 端缓冲的大小,可以避免频繁的磁盘 IO 操作,进而提升 Spark
任务的整体性能。
map 端缓冲的默认配置是 32KB,如果每个 task 处理 640KB 的数据,那么会发生 640/32
= 20 次溢写,如果每个 task 处理 64000KB 的数据,机会发生 64000/32=2000 此溢写,这对
于性能的影响是非常严重的。

map 端缓冲的配置方法如代码清单所示:

val conf = new SparkConf()
 .set("spark.shuffle.file.buffer", "64")

2.调整reduce端拉取数据缓冲区的大小

Spark Shuffle 过程中,shuffle reduce task 的 buffer 缓冲区大小决定了 reduce task 每次能够缓冲的数据量,也就是每次能够拉取的数据量,如果内存资源较为充足,适当增加拉取数
据缓冲区的大小,可以减少拉取数据的次数,也就可以减少网络传输的次数,进而提升性能。
reduce 端数据拉取缓冲区的大小可以通过 spark.reducer.maxSizeInFlight 参数进行设置,默认
为 48MB,该参数的设置方法如代码清单所示:

val conf = new SparkConf()
.set("spark.reducer.maxSizeInFlight", "96")

3.调整reduce端拉取数据重试的次数

Spark Shuffle 过程中,reduce task 拉取属于自己的数据时,如果因为网络异常等原因导
致失败会自动进行重试。对于那些包含了特别耗时的 shuffle 操作的作业,建议增加重试最
大次数(比如 60 次),以避免由于 JVM 的 full gc 或者网络不稳定等因素导致的数据拉取失
败。在实践中发现,对于针对超大数据量(数十亿~上百亿)的 shuffle 过程,调节该参数可
以大幅度提升稳定性。
reduce 端拉取数据重试次数可以通过 spark.shuffle.io.maxRetries 参数进行设置,该参数
就代表了可以重试的最大次数。如果在指定次数之内拉取还是没有成功,就可能会导致作业
执行失败,默认为 3,该参数的设置方法如代码清单所示:

val conf = new SparkConf()
 .set("spark.shuffle.io.maxRetries", "6")

4.调整reduce端拉取数据等待间隔

Spark Shuffle 过程中,reduce task 拉取属于自己的数据时,如果因为网络异常等原因导
致失败会自动进行重试,在一次失败后,会等待一定的时间间隔再进行重试,可以通过加大
间隔时长(比如 60s),以增加 shuffle 操作的稳定性。
reduce 端拉取数据等待间隔可以通过 spark.shuffle.io.retryWait 参数进行设置,
默认值为 5s,该参数的设置方法如代码清单所示:

val conf = new SparkConf()
 .set("spark.shuffle.io.retryWait", "60s")

5.调整SortShuffle排序操作阈值

对于 SortShuffleManager,如果 shuffle reduce task 的数量小于某一阈值则 shuffle write 过
程中不会进行排序操作,而是直接按照未经优化的 HashShuffleManager 的方式去写数据,但
是最后会将每个 task 产生的所有临时磁盘文件都合并成一个文件,并会创建单独的索引文
件。
当你使用 SortShuffleManager 时,如果的确不需要排序操作,那么建议将这个参数调大
一些,大于 shuffle read task 的数量,那么此时 map-side 就不会进行排序了,减少了排序的
性能开销,但是这种方式下,依然会产生大量的磁盘文件,因此 shuffle write 性能有待提高。
SortShuffleManager 排序操作阈值的设置可以通过 spark.shuffle.sort. bypassMergeThreshold 这
一参数进行设置,默认值为 200,该参数的设置方法如代码清单所示:

val conf = new SparkConf()
 .set("spark.shuffle.sort.bypassMergeThreshold", "400")

猜你喜欢

转载自blog.csdn.net/weixin_48929324/article/details/118864057