要想理解MapReduce过程中哪些阶段有的排序,就必须要明白MapReduce的过程。
这篇博客很详细的讲解了MapReduce的过程:MapReduce过程详解
下面我再简述一下mapreduce的过程
MapReduce过程概述
MapReduce一共可分为三个阶段:map,shuffle,reduce过程
map阶段主要就是进行值到键值对的映射。shuffle过程对map的输出数据进行重新洗牌分区排序分发给相应的reduce。reduce则接收数据进行相应聚合操作。
这里要提到的是,实际上MapReduce也可以看做只有两个过程,那就是Map和Reduce,那么shuffle则可以划分为两部分,分为Map端的shuffle和Reduce端的shuffle。因此无论MapReduce是被划分为两个阶段还是三个阶段,本质上是不变的。
下面简单介绍MapReduce过程:
map过程:
- 第一阶段:针对一个文件,hdfs中对其是分块存储的,因此每一个数据块都会由一个Mapper进程接收处理。
- 第二阶段:解析数据映射键值对。有个默认规则是把每一行文本内容解析成键值对,这里的“键”是每一行的起始位置(单位是字节),“值”是本行的文本内容。
- 第三阶段:调用Mapper类中的map方法,在第二阶段中解析出来的每一个键值对,调用一次map方法(其实就是每一行划分,映射),如果有1000个键值对,就会调用1000次map方法,每一次调用map方法会输出零个或者多个键值对。
到此我们所认为的map阶段就结束了,因为数据已经从map输出了,下面就是shuffle过程。
map端的shuffle过程:
-
Collect阶段:Map 函数开始产生输出时,并不是简单地把数据写到磁盘中,因为频繁的磁盘操作会导致性能严重下降。它的处理过程是把数据首先写到内存中的一个缓冲区,以提升效率。
-
Spill 阶段:当缓冲区中的数据量达到一个特定阈值(默认是 80%)时,系统将会启动一个后台线程,把缓冲区中的内容写到磁盘中(即 Spill 阶段)。在写磁盘前,线程首先根据数据最终要传递到的 Reduce 任务把数据划分成相应的分区(Partition)。在每个分区中,后台线程按 Key 进行排序,如果有一个 Combiner,便会在排序后的输出上运行。
在写磁盘过程中,Map 输出继续被写到缓冲区中,但如果在此期间缓冲区被填满,那么 Map 任务就会阻塞直到写磁盘过程完成
注意: 这里要注意的两个地方:第一个就是在这里要进行分区了,默认的分区方法是进行哈希。第二个就是同时在每个分区都要进行一次排序。因此最终落到磁盘的每个文件都是有序的。
- Merge 阶段:一旦内存缓冲区达到溢出写的阈值,就会创建一个溢出写文件,因此在 Map 任务完成其最后一个输出记录后,便会有多个溢出写文件。在 Map 任务完成前,溢出写文件被合并成一个索引文件和数据文件。把所有溢出的临时文件进行一次合并操作,以确保一个MapTask最终只产生一个中间数据文件。
到此map端就已经完成了,已经将中间数据生成了。并且做了分区和排序。
reduce端的shuffle过程:
-
Copy阶段: ReduceTask启动Fetcher线程到已经完成MapTask的节点上复制一份属于自己的数据,这些数据默认会保存在内存的缓冲区中,当内存的缓冲区达到一定的阀值的时候,就会将数据写到磁盘之上。
-
Merge阶段:在ReduceTask远程复制数据的同时,会在后台开启两个线程(一个是内存到磁盘的合并,一个是磁盘到磁盘的合并)对内存到本地的数据文件进行合并操作。
-
Sort阶段:在对数据进行合并的同时,会进行排序操作,由于MapTask 阶段已经对数据进行了局部的排序,ReduceTask只需保证Copy的数据的最终整体有效性即可。
最终文件可能存在于磁盘中,也可能存在于内存中,但是默认情况下是位于磁盘中的。当 Reduce 的输入文件已定,整个 Shuffle阶段就结束了,然后就是 Reduce 执行,把结果放到 HDFS 中(Reduce 阶段)。
注意: ReduceTask再数据合并的过程中同样会进行排序,这样,数据便按照Key分成了若干组,之后以组为单位交给reduce()处理。
reduce过程
- Reduce在接收到数据之后,对排序后的键值对调用reduce方法,键相等的键值对调用一次reduce方法,每次调用会产生零个或者多个键值对,最后把这些输出的键值对写入到HDFS文件中。
排序发生的阶段
如果你看懂了上述的过程,那么很容易的就会有答案了:排序一共会发生在两个阶段,一个是map端的shuffle阶段,另一个是reduce端的shuffle阶段。(也可以说是map端有一次排序,reduce端也有一次排序)
这两个排序阶段是不可避免的
Combiner误区
很多人以为如果不用Combiner,map端就不会排序了,实际上还是会有的