文章目录
- 1.Shuffle 核心要点
- 1.1 ShuffleMapStage 与 FinalStage
- 1.2 Shuffle中的任务个数
- 1.3 reduce端数据读取
- 2.HashShuffle解析
- 2.1 未经优化的HashShuffleManager
- 2.2 经过优化的HashShuffleManager
- 3.SortShuffle解析
- 3.1 普通运行机制
- 3.2 bypass运行机制
1.Shuffle 核心要点
1.1 ShuffleMapStage 与 FinalStage
在划分Stage时,Action算子前的最后一个Stage称为FinalStage
(其实就是ResultStage对象),前面的所有Stage称为ShuffleMapStage
ShuffleMapStage
的结束伴随着shuffle文件的写磁盘
ResultStage
基本上对应于代码中的action算子,一个action算子的结束,表示一个Job的结束
1.2 Shuffle中的任务个数
Shuffle分为Shuffle Read
和Shuffle Write
两个阶段,也称为map阶段和reduce阶段,而这两个阶段都会分为若干个task来进行,task数量又是由什么决定的呢?
假设Spark从HDFS中读取数据,那么初始RDD的分区个数由该文件的split
个数决定,也就是一个split
对应生成RDD的一个partition
。
reduce端的stage默认去spark.default.parallelism
配置项作为分区数,如果没有配置则取map端的最后一个RDD的分区数。
1.3 reduce端数据读取
- map task执行完毕之后会将任务执行状态和写入磁盘文件的位置告知Driver
- reduce task要获取数据时,会向Driver请求获取任务所需要数据的位置,之后去对应的节点上获取。
2.HashShuffle解析
2.1 未经优化的HashShuffleManager
每个map task生成和reduce task数量相等的磁盘文件
问题: 生成大量的小文件
2.2 经过优化的HashShuffleManager
设置参数spark.shuffle.consolidateFiles
新的map task来了会复用上一个map task生成的文件,不会继续产生新的文件(相当于每个CPU只生成和reduce task数量相等的磁盘文件)
3.SortShuffle解析
3.1 普通运行机制
- 数据写写入一个数据结构(数据结构根据不同的shuffle算子进行选择,如reduceByKey这种聚合类算子:Map结构,会一边进行聚合一边写入内存)
- 每往数据结构写一条数据,就会判断是否达到某个阈值,达到阈值之后就会将数据结构中的数据溢写到磁盘,同时清空内存数据结构
- 溢写到磁盘文件之前,会先根据key对内存数据结构中已有的数据进行排序,排序过后,写入内存缓冲区,再会分批将数据写入磁盘(写入磁盘文件是通过Java的
BufferedOutputStream
实现的,只有当内存缓冲溢满之后再一次写入磁盘中,这样可以减少磁盘IO次数,提升性能)
[外链图片转存失败(img-KiJ7y6tq-1562515948548)(./pic/SortShuffle.png)] - 多个磁盘文件会合并,最后会合并成一个大的磁盘文件,同时还会生成一个索引文件(告诉reduce task它所需要的数据在大文件的起始终止位置),
3.2 bypass运行机制
该运行机制的触发条件是:
- shuffle map task数量小于
spark.shuffle.sort.bypassMergeThreshold
参数的值 - 不是聚合类的shuffle算子
其实与未经优化HashShuffleManager
的机制几乎一样,会产生许多的小文件,只不过最后会有合并成一个大文件(同时还有一个索引文件)