概述
- MapReduce 中, Map 阶段处理的数据如何传递给 Reduce 阶段,是 - MapReduce 框架中最关键的一个流程,这个流程就叫 Shuffle
- Shuffle: 数据混洗 ——(核心机制:数据分区,排序,缓存)
- 具体来说:就是将 MapTask 输出的处理结果数据,分发给 ReduceTask,并在分发的过程中,对数据按 key 进行了分区和排序。
主要流程图
- Shuffle 是 MapReduce 处理流程中的一个过程,它的每一个处理步骤是分散在各个 MapTask 和 ReduceTask 节点上完成的,整体来看,分为 3个操作:
(1)Partition(分区,必要)
(2)Sort (根据 key 排序,必要)
(3)Combiner (进行局部 value 的合并,非必要)
详细流程
- 1.Collect 阶段:MapTask 收集我们的 map()方法输出的 kv 对,放到内存缓冲区中。
注意:每个MapTask都有一个环形内存缓冲区,用于储存任务的输出 - 2.Spill 阶段:内存中的数据量达到一定的阈值80%,一个后台线程就会不断地将数据溢出到本地磁盘文件,可能会溢出多个文件。在写磁盘过程中,map 输出继续被写到缓冲区,但如果在此期间缓冲区被填满,map 会阻塞直到写磁盘过程完成,而不会覆盖缓冲区中已有的数据。
在写磁盘前,线程首先根据数据最终要传送到的 Reducer(通过调用 Partitioner 的 getPartition() 方法就能知道该输出要送往哪个 Reducer) 把数据划分成相应的分区(partition)。在每个分区中,后台线程按键进行内排序,如果有 Combiner,还要对排序后的数据进行 Combiner。 - 3.Merge 阶段:当整个 MapTask 的记录全部写完后,这些溢出文件会被合并为一个分区且排序的文件。
- 4.Copy 阶段:ReduceTask根据自己的分区号,去各个MapTask机器上取相应的结果分区数据。每个 MapTask 的完成时间可能不同,因此只要有一个任务完成,ReduceTask 就开始复制(copy)其输出。
- 5.Merge阶段: 在 ReduceTask 远程复制数据的同时,ReduceTask会对同一个分区的来自不同MapTask的结果文件进行合并。
- 6.Sort阶段:在对数据进行合并的同时,会进行排序操作,由于 MapTask 阶段已经对数据进行了局部的排序,ReduceTask 只需做一次归并排序就可以保证 Copy 的数据的整体有效性。
- 7.合并成大文件后,Shuffle的过程也就结束了,后面进入ReduceTask的逻辑运算过程(从文件中取出一个一个的键值对,调用用户自定义的reduce()方法)
总结
- 1.Map 阶段的输出是写入本地磁盘而不是 HDFS,但是一开始数据并不是直接写入磁盘而是缓冲在内存中。
- 2.缓存的好处就是减少磁盘 I/O 的开销,提高合并和排序的速度。
- 3.内存缓冲区的大小默认是 100M(原则上说,缓冲区越大,磁盘 io 的次数越少,执行速度就越快。缓冲区的大小可以通过 --mapreduce.task.io.sort.mb 参数调整),所以在编写 map 函数的时候要尽量减少内存的使用,为 Shuffle 过程预留更多的内存,因为该过程是最耗时的过程。