MapReduce主要分为三个阶段,Map阶段,Shuffle阶段,Reduce阶段。
Map阶段:
将输入的多个分片(Split)有Map任务以完全并行方式进行处理。一个分片对应一个map任务,在默认的情况下,分片的大小与HDFS中数据块(Block)大小一致,可以通过调整HDFS中block的大小来控制map的任务数量。
每个Map任务对输入分片中的数据按照一定的规则解析成多个KV键值对,默认是把每一行文本内容解析成一个KV键值对,key为每一行的其实位置,即每一行的偏移量,value为本行的文本内容,然后将解析出来所有的KV键值对输入到map()方法中进行处理,map()方法一次处理一个KV键值对数据,将处理结果让然是以KV键值对形式进行输出。
为了减小磁盘的I/O,Map任务输出的KV键值对会先存储在Map任务的所在节点下的内存缓冲区中,缓冲区的大小默认为100MB(可以通过*mapreduce.task.io.sort.mb
* 属性调整)。当缓冲区的数据量达到预先设置的阈值后(mapreduce.map.sort.spill.percent
属性的值,默认为0.8,即80%),便会将缓冲区的数据溢写(spill)到磁盘(mapreduce.cluster.local.dir
属性的指定目录,默认为${hadoop.tmp.dir}/mapred/local
)的临时文件中。当map任务输出最后一个记录是,可能会产生很火的溢出文件,这是需要将文件进行合并,合并的过程中会不断地进行排序(默认是升序)和combine操作,目的有两个:1、尽量减少每次写入磁盘的数据量;2、尽量减少下一复制阶段网络传输的数据量。
在数据溢写到磁盘之前会对数据进行分区(Partition)。分区的数量与设置的Reduce任务数量相同(默认Reduce任务数量为1,)这样一个Reduce任务会处理一个分区的数据,从而实现了负载均衡,避免了数据倾斜。 数据分区的规则:去KV键值对中key的hashCode值然后除以Reduce任务的数量后然后进行取余,余数则是分区编号,分区编号一致则会被分到同一个分区,因为Reduce任务数默认为1,任何数字除以1的余数都是0,所以分区编号从0开始。
Reduce阶段:
首先会对Map阶段的数据结果按照分区进行一次合并,将用一个分区的KV键值对合并到一起,然后按照key对分区中KV键值对进行排序 。
每个分区排序后的kv键值对会按照key进行分组,key相同额kv键值对将合并为<key, value-list>对,最终每个分区形成多个<key, value-list>对。排序后的分区数据会输入到reduce()方法中进行处理。
Shuffle阶段
shuffle阶段数位于Map任务输出之后,Recude任务接收之前,shuffle阶段主要是将map任务无规则输出型有一定有规则的数据一遍reduce任务进行处理。
以上整理自《hadoop大数据技术开发实战》,shuffle以后再做详细分析记录。