5、Shuffle机制
Spark的Shuffle是把一组无规则的数据尽量转换为一组具有一定规则的数据,Spark的Shuffle和MapReduce的Shuffle思想相同,在实现细节和优化方式上不同。
Shuffle就是包裹在各种需要重分区的算子之下的一个对数据进行重新组合的过程。
5.1、Shuffle阶段
Shuffle分为两个阶段:Shuffle Write和Shuffle Fetch。
在Spark中,整个Job转化为一个有向无环图(DAG)执行,DAG是在每个Stage的承接阶段做Shuffle过程。
下图为Shuffle阶段图:
上图分析:
整个Job分为Stage0~Stage3,4个Stage。
首先从最上端的Stage2、Stage3执行,每个Stage对每个分区执行变换(Transformation)的流水线式的函数操作,执行到每个Stage的最后阶段进行Shuffle Write,将数据重新根据下一个Stage分区数分成相应的Bucket,并将Bucket最后写入磁盘。整个过程就是Shuffle Write阶段。
执行完Stage2、Stage3之后,Stage1去存储有Shuffle数据节点的磁盘Fetch需要的数据,将数据Fetch到本地之后进行用户定义的聚集函数操作。这个阶段叫Shuffle Fetch。
Shuffle Fetch包含聚集阶段,这样一轮一轮的Stage之间就完成了Shuffle操作。
5.2、Shuffle Write流程
Spark的在每个Stage中是通过任务执行来进行计算的,而Spark中只分为两种任务:ShuffleMapTask和ResultTask。其中ResultTask就是最底层的Stage,也就是整个任务执行的最后阶段将数据输出到Spark执行空间Stage。除了这个阶段执行ResultTask,其余阶段都执行ShuffleMapTask。
下图为Shuffle Write流程
上图是进行Shuffle的整体流程,假定该Shuffle中有3个Mapper和2个Reducer,这样就会产生3*2=6个Bucket,也就是会产生6个Shuffle文件。
因此产生的Shuffle文件个数为M*R,M是Map任务个数,R是Reduce任务数。
5.3、Shuffle Fetch流程
Shuffle Write阶段写到各个节点的数据,Reducer端的节点通过拉去数据而获取需要的数据,这个过程在Spark中叫Fetch。
这就需要Shuffle Fetch将所需要的数据来过来,fetch包括本地和远端,因为Shuffle数据有可能一部分存储在本地。
Spark使用2套框架实现Shuffle Fetch:NIO通过Socket连接去fetch数据,OIO通过Netty去Fetch数据。
上图分析如下:
这个Job有两个Stage,在Stage1和Stage0之间做Shuffle Fetch操作。
HadoopRDD的每个B代表HDFS的一个分区,读入后通过映射转化为MapPartitionsRDD,
做完Shuffle Write之后,Shuffle数据按照Bucket存储磁盘。Stage0的每个Task通过元数据知道数据存储在哪个节点,到该节点Fetch需要的指定Key的数据。在Stage0将Fetch到的数据形成分区,所有的分区形成ShuffleRDD。
通过聚集函数将ShuffleRDD每个分区中的每条数据存储到AppendOnlyMap(一个Spark封装的哈希表)中,在这个过程中执行用户定义的聚集函数,做聚集操作。最后将形成的结果形成分区,所有分区形成MapPartitionRDD.
Shuffle fETCH和聚集Aggregate的操作过程是边Fetch数据边处理,不是一次Fetch完再处理。
Hadoop MapReduce的Shuffle过程中,Shuffle Fetch过来的数据都会进行归并排序(merge sort),使相同Key下的不同Value按序归并到一起供Reducer使用。
在Spark并不是所有的情况下Aggregator都需要排序,强制的排序只会增加不必要的开销。
Spark和MapReduce都存放在磁盘上
Spark shuffle:http://blog.csdn.net/johnny_lee/article/details/22619585