一、Hadoop Shuffle 与 Spark Shuffle 的区别
### --- 共同点:
~~~ 二者从功能上看是相似的;从High Level来看,没有本质区别,实现(细节)上有区别
### --- 实现上的区别:
~~~ Hadoop中有一个Map完成,Reduce便可以去fetch数据了,不必等到所有Map任务完成;
~~~ 而Spark的必须等到父stage完成,也就是父stage的 map 操作全部完成才能去fetch数据。
~~~ 这是因为spark必须等到父stage执行完,才能执行子stage,主要是为了迎合stage规则
~~~ Hadoop的Shuffle是sort-base的,那么不管是Map的输出,还是Reduce的输出,
~~~ 都是partition内有序的,而spark不要求这一点
~~~ Hadoop的Reduce要等到fetch完全部数据,才将数据传入reduce函数进行聚合,
~~~ 而 Spark是一边fetch一边聚合
二、Shuffle优化
### --- Shuffle优化
~~~ Spark作业的性能主要就是消耗了shuffle过程,
~~~ 因为该环节包含了众多低效的IO操作:磁盘IO、序列化、网络数据传输等;
~~~ 如果要让作业的性能更上一层楼,就有必要对 shuffle 过程进行调优。
~~~ 但必须注意的是,影响Spark作业性能的因素,主要还是代码质量、资源参数以及数据倾斜,
~~~ shuffle调用只能在整个Spark的性能调优中占到一小部分而已。
### --- 开发过程中对 Shuffle 的优化:
~~~ 减少Shuffle过程中的数据量
~~~ 避免Shuffle
~~~ 以下介绍 Shuffle 的优化主要是参数优化:
三、Shuffle优化流程
### --- 优化一:
~~~ 调节 map 端缓冲区大小
~~~ spark.shuffle.file.buffer 默认值为32K,shuffle write阶段buffer缓冲大小。
~~~ 将数据写到磁盘文件之前,会先写入buffer缓冲区,缓冲写满后才溢写到磁盘
~~~ 调节map端缓冲的大小,避免频繁的磁盘IO操作,进而提升任务整体性能
~~~ 合理设置参数,性能会有 1%~5% 的提升
### --- 优化二:
~~~ 调节 reduce 端拉取数据缓冲区大小
~~~ spark.reducer.maxSizeInFlight 默认值为48M。
~~~ 设置shuffle read阶段buffer缓冲区大小,这个buffer缓冲决定了每次能够拉取多少数据
~~~ 在内存资源充足的情况下,可适当增加参数的大小(如96m),
~~~ 减少拉取数据的次数及网络传输次数,进而提升性能
~~~ 合理设置参数,性能会有 1%~5% 的提升
### --- 优化三:
~~~ 调节 reduce 端拉取数据重试次数及等待间隔
~~~ Shuffle read阶段拉取数据时,如果因为网络异常导致拉取失败,会自动进行重试
~~~ spark.shuffle.io.maxRetries,默认值3。最大重试次数
~~~ spark.shuffle.io.retryWait,默认值5s。每次重试拉取数据的等待间隔
~~~ 一般调高最大重试次数,不调整时间间隔
### --- 优化四:
~~~ 调节 Sort Shuffle 排序操作阈值
~~~ 如果shuffle reduce task的数量小于阈值,则shuffle write过程中不会进行排序操作,
~~~ 而是直接按未经优化的Hash Shuffle方式写数据,
~~~ 最后将每个task产生的所有临时磁盘文件都合并成一个文件,并创建单独的索引文件
~~~ spark.shuffle.sort.bypassMergeThreshold,默认值为200
~~~ 当使用SortShuffleManager时,如果的确不需要排序操作,建议将这个参数调大
### --- 优化五:调节 Shuffle 内存大小
~~~ Spark给 Shuffle 阶段分配了专门的内存区域,这部分内存称为执行内存
~~~ 如果内存充足,而且很少使用持久化操作,建议调高这个比例,
~~~ 给 shuffle 聚合操作更多内存,以避免由于内存不足导致聚合过程中频繁读写磁盘
~~~ 合理调节该参数可以将性能提升10%左右