HashShuffle(1.6后已经取消)
流程图
通过该流程图可以看出,HashShuffle的最大缺点就是在写入磁盘时,会产生大量文件,文件为为 ReduceTask的个数×MapTask个数,因此有了一种对HashShuffle过程进行优化的shuffle过程,他减少了写入磁盘的文件数,同一个core上调用的不同task共享同一个缓冲区与磁盘文件,这样就减小了文件数,文件数=该任务使用的core数×reduceTask个数
SortShuffle
流程图
由图可见,SortShuffle在向磁盘写文件时,不受ReduceTask的影响,他是没达到一次阈值,就进行一次刷写,并且阈值的大小时动态申请的(如果申请不到内存,就视为达到阈值)。其次,在向磁盘进行刷写之前,SortShuffle会对数据进行排序,然后才会将内存中的数据刷写到磁盘。最后,SortShuffle会将磁盘和内存中未刷写的数据进行合并,形成两个文件(合并后的大文件和索引文件),索引文件用来告诉各ReduceTask要取的数据范围。
PassByMergeSortShuffle
PassByMergeSortShuffle类似与HashShuffle,但在他在HashShuffle的基础上,将写到磁盘中的文件进行一个合并,这有点类似于SortShuffle。
通过查看PassByMergeSortShuffle的源码,发现PassByMergeSortShuffle必须满足两个条件:
def shouldBypassMergeSort(conf: SparkConf, dep: ShuffleDependency[_, _, _]): Boolean = {
// We cannot bypass sorting if we need to do map-side aggregation.
if (dep.mapSideCombine) {
require(dep.aggregator.isDefined, "Map-side combine without Aggregator specified!")
false
} else {
val bypassMergeThreshold: Int = conf.getInt("spark.shuffle.sort.bypassMergeThreshold", 200)
dep.partitioner.numPartitions <= bypassMergeThreshold
}
}
(1)action不是聚合类的算子,即提前进行预聚合;原因是因为PassByMergeSortShuffle过程并没有排序操作,因此无法进行预聚合。
(2)分区数小于200;分区数可以影响Task的个数,从而产生大量小文件。