在Map和Reduce之间的过程就是Shuffle,Shuffle的性能直接影响整个Spark的性能。所以Shuffle至关重要。
Shuffle 介绍
从图中得知,Map输出的结构产生在bucket中。而bucket的数量是map*reduce的个数。这里的每一个bucket都对应一个文件。Map对bucket书是写入数据,而reduce是对bucket是抓取数据也就是读的过程。
在spark1.1.1中shuffle过程的处理交给了ShuffleBlockManager来管理。
ShuffleManager
ShuffleManager中有四个方法:
1)registerShuffleShuffle注册
2)getWriter获得写数据的对象
3)getReader获得读取数据的对象
4)unregisterShuffle移除元数据
5)Stop 停止ShuffleManager
ShuffleManager有两个子类:
Shuffle Write
Shuffle写的过程需要落地磁盘。在参数
中可以配置。
接下来看下write的具体方法
如果consolidateShuffleFiles为true写文件,为false在completedMapTasks中添加mapId。
接下来看下recycleFileGroup这个方法。参数ShuffleFileGroup是一组shuffle文件,每一个特定的map都会分配一组ShuffleFileGroup写入文件。代码如下:
这里的valunusedFileGroups = new ConcurrentLinkedQueue[ShuffleFileGroup]()是一个链表队列。往队列中添加shuffleFileGroup
而在shuffleState.comletedMapTasks这个方法则是往bucket中填充,如果consolidateShuffleFiles为FALSE,则不需要管他。源码中也是这样解释completedMapTasks这个队列:
源码中的ShuffleState是记录shuffle的一个特定状态。
ShuffleWrite有两个子类:
HashShuffleWriter中的写方法:
再来看下SortShuffleWriter的write方法:
ShuffleReader
HashShuffleReader
SortShuffleManager中的读取对象调用了HashShuffleReader
在Spark1.1.1源码中SortShuffleManager压根就没实现。
Shuffle partition
在RDD API中当调用reduceByKey等类似的操作,则会产生Shuffle了。
根据不同的业务场景,reduce的个数一般由程序猿自己设置大小。可通过“spark.default.par allelism”参数设置。
1、在第一个MapPartitionsRDD这里先做一次map端的聚合操作。
2、ShuffledRDD主要是做从这个抓取数据的工作。
3、第二个MapPartitionsRDD把抓取过来的数据再次进行聚合操作。
4、步骤1和步骤3都会涉及到spill的过程。
在作业提交的时候,DAGSchuduler会把Shuffle的成过程切分成map和reduce两个部分。每个部分的任务聚合成一个stage。
Shuffle在map端的时候通过ShuffleMapTask的runTask方法运行Task。
ShuffleMapTask结束之后,最后走到DAGScheduler的handleTaskCompletion方法当中源码如下:
Stage结束后,到reduce抓取过程。查看BlockStoreShuffleFetcher源码如下: