一、概述
MapReduce会确保每个reducer的输⼊都是按键排序的。从map⽅法输出数据开始、到作为输⼊数据传给reduce⽅法的过程称为shuffle。在此,我们将学习shuffle是如何⼯作的,因为它有助于我们理解⼯作机制(如果需要优化MapReduce程序)。shuffle属于不断被优化和改进的代码库的⼀部分,因此会随着版本的不同,细节上可能会发⽣变量。不管怎样,从许多⽅⾯来看,shuffle是MapReduce的“⼼脏 “,是奇迹发⽣的地⽅。

二、环形缓冲区
每个map任务都会有⼀个环形内存缓冲区⽤于存储map的输出数据。在默认情况下,缓冲区的⼤⼩为100MB,这个值可以通过mapreduce.task.io.sort.mb属性来调整。⼀旦缓冲区的内容达到阙值(默认是0.8,或者是80%,属性是mapreduce.map.sort.spill.percent),⼀个后台线程便开始把内容溢写(spill)到磁盘⾥,这个位置由属性mapreduce.cluster.local.dir来指定的。在将数据溢写到磁盘过程中,map的输出数据继续写到缓冲区,但如果在此期间缓冲区被填满,map会被阻塞直到写磁盘过程完成。
环形缓冲区:其实是⼀个字节数组kvbuffer. 有⼀个sequator标记,kv原始数据从左向右填充(顺时针),
kvmeta是对kvbuffer的⼀个封装,封装成了int数组,⽤于存储kv原始数据的对
应的元数据valstart,keystart,partition,vallen信息,从右向左(逆时针)。


三、shuffle整体流程图
shuffle阶段是处于map阶段到reduce阶段的一个过程
a) 完整地从map task端拉取数据到reduce 端。
b) 在跨节点拉取数据时,尽可能地减少对带宽的不必要消耗。
c) 减少磁盘IO对task执⾏的影响。
四、shuffle流程
1. 从map函数输出到reduce函数接受输⼊数据,这个过程称之为shuffle.
2. map函数的输出,存储环形缓冲区(默认⼤⼩100M,阈值80M)
3. 当达到阈值时,准备溢写到本地磁盘(因为是中间数据,因此没有必要存储在HDFS上)。在溢写前要进⾏对元数据分区(partition)整理,然后进⾏排序(quick sort,通过元数据找到出key,同⼀分区的所有key进⾏排序,排序完,元数据就已经有序了,在溢写时,按照元数据的顺序寻找原始数据进⾏溢写)
4. 如果有必要,可以在排序后,溢写前调⽤combiner函数进⾏运算,来达到减少数 据的⽬的
5. 溢写⽂件有可能产⽣多个,然后对这多个溢写⽂件进⾏再次合并(也要进⾏分区和排序)。当溢写个数>=3时,可以再次调⽤combiner函数来减少数据。如果溢写个数<3时,默认不会调⽤combiner函数。
6. 合并的最终溢写⽂件可以使⽤压缩技术来达到节省磁盘空间和减少向reduce阶段传输数据的⽬的。(存储在本地磁盘中)
7. Reduce阶段通过HTTP写抓取属于⾃⼰的分区的所有map的输出数据(默认线程数是5,因此可以并发抓取)。
8. 抓取到的数据存在内存中,如果数据量⼤,当达到本地内存的阈值时会进⾏溢写操作,在溢写前会进⾏合并和排序(排序阶段),然后写到磁盘中,
9. 溢写⽂件可能会产⽣多个,因此在进⼊reduce之前会再次合并(合并因⼦是10),最后⼀次合并要满⾜10这个因⼦,同时输⼊给reduce函数,⽽不是产⽣合并⽂件。reduce函数输出数据会直接存储在HDFS上。
本文深入解析MapReduce中的shuffle过程,包括环形缓冲区的工作原理、shuffle的整体流程及具体步骤。了解这些有助于优化MapReduce程序。

939

被折叠的 条评论
为什么被折叠?



