MapReduce阶段划分

1、阶段划分

MapReduce执行的4个阶段,分别为Split阶段—> Map阶段 —> Shuffle阶段 —> Reduce阶段。
在这里插入图片描述

第一阶段:Split输入分片阶段

1、输入分片

输入分片,是逻辑分片,所谓逻辑分片就是根据文件的字节索引进行分割,比如0-1MB位置定义为第一个分片,1MB-2MB定义为为第二个分片,依次类推……而原来的大文件还是原来的大文件,不会受到影响,因此,输入分片(input split)存储的并非数据本身,而是一个分片长度和一个记录数据的位置的数组。

2、分片数量与Map Task数量的关系

Map Task的个数等于split的个数。mapreduce在处理大文件的时候,会根据一定的规则,把大文件划分成多个分片,这样能够提高map的并行度。 划分出来的就是InputSplit,每个map处理一个InputSplit,因此,有多少个InputSplit,就有多少个map task。

3、由谁来划分分片

主要是InputFormat类来负责划分Split。InputFormat类有2个重要的作用:
1)将输入的数据切分为多个逻辑上的InputSplit,其中每一个InputSplit作为一个map的输入。
2)提供一个RecordReader,用于将InputSplit的内容转换为可以作为map输入的k,v键值对。

4、分片的大小由谁来决定?

每个输入分片的大小是固定的,默认情况下,输入片(InputSplit)的大小与数据块(Block)的大小是相同的。Hadoop 2.x默认的block大小是128MB,Hadoop 1.x默认的block大小是64MB,可以在hdfs-site.xml中设置dfs.block.size,注意单位是byte。

5、默认分片大小与Block分块大小是相同的原因

hadoop在存储有输入数据(HDFS中的数据)的节点上运行map任务,可以获得高性能,这就是所谓的数据本地化。所以最佳分片的大小应该与HDFS上的块大小一样,因为如果分片跨越2个数据块,对于任何一个HDFS节点(Hadoop系统保证一个块存储在一个datanode上,基本不可能同时存储这2个数据块),分片中的另外一块数据就需要通过网络传输到map任务节点,与使用本地数据运行map任务相比,效率则更低!优点就是可以实现分块优化,减少网络传输数据,使用本地数据运行map任务。

第二阶段:Map阶段

每个Mapper任务是一个java进程,它会读取HDFS文件中自己对应的输入切片,将切片中记录按照一定的规则解析成很多的键值对,有个默认规则是把每一行文本内容解析成键值对,这里的“键”是每一行的起始位置(单位是字节),“值”是本行的文本内容,也就是我们图中定义为<k1,v1>。然后经过我们重写的map方法处理,针对解析出来的每一个键值对<k1,v1>,都分别调用一次map方法,如果有1000个键值对,就会调用1000次map方法,每一次调用map方法会输出零个或者多个键值对,这里输出的键值对,也就是我们图中定义的,比如我们单词统计案例中其中的一个<k1,v1>为<0,‘Dear Bear River’>,经一次map处理后变为3个<k2,v2>,即<‘Dear’,1>、<‘Bear’,1>和<‘River’,1>。

第三阶段:Shuffle阶段

Shuffle阶段也称为洗牌阶段,该阶段是将输出的<k2,v2>传给Shuffle(洗牌),Shuffle完成对数据的分区、排序和合并等操作。Shuffle过程包含在Map和Reduce两端,即Map shuffle和Reduce shuffle, Shuffle描述着数据从map task流向reduce task的这段过程,具体过程如图:
在这里插入图片描述

1、Map端的Shuffle

1)每个输入分片会让一个 Map 任务来处理,默认情况下,以 HDFS 的一个块的大小(默认为 128MB)为一个分片。Map函数开始产生输出时,并不是简单地把数据写到磁盘中,因为频繁的磁盘操作会导致性能严重下降。它的处理过程是把数据首先写到内存中的一个缓冲区, 并做一些预排序,以提升效率。

2)每个 Map 任务都有一个用来写入输出数据的循环内存缓冲区(默认大小为 128MB),当缓冲区中的数据量达到一个特定阈值(默认是 80%)时,系统将会启动一个后台线程,把缓冲 区中的内容写到磁盘中(即 Spill 阶段)。在写磁盘过程中,Map 输出继续被写到缓冲区中,但如果在此期间缓冲区被填满,那么 Map 任务就会阻塞直到写磁盘过程完成。

3)在写入磁盘之前,线程首先根据reduce任务的数目将数据划分为相同数目的分区(Partition),也就是一个reduce任务对应一个分区的数据。这样做是为了避免有些reduce任务分配到大量数据,而有些reduce任务却分到很少数据,甚至没有分到数据的尴尬局面。其实分区就是对数据进行hash的过程。然后对每个分区中的数据进行排序,如果此时设置了Combiner,将排序后的结果进行Combine操作,这样做的目的是让尽可能少的数据写入到磁盘。

4)当map任务输出最后一个记录时,可能会有很多的溢出文件,这时需要将这些文件合并。合并的过程中会不断地进行排序和Combine操作,目的有两个:①尽量减少每次写入磁盘的数据量。②尽量减少下一复制阶段网络传输的数据量。最后合并成了一个已分区且已排序的文件。为了减少网络传输的数据量,这里可以将数据压缩,只要将mapred.compress.map.out设置为true就可以了。

5)溢出写文件归并完毕后,Map 任务将删除所有的临时溢出写文件,并告知 TaskTracker 任务已完成,只要其中一个 Map 任务完成,Reduce 任务就会开始复制它的输出(Copy 阶段)。

6)Map 任务的输出文件放置在运行 Map 任务的 TaskTracker 的本地磁盘上,它是运行 Reduce 任务的 TaskTracker 所需要的输入数据。
在这里插入图片描述

2、Reduce 端的 Shuffle 阶段

1)Reduce 进程启动一些数据复制线程,请求 Map 任务所在的 TaskTracker 以获取输出文件,并且每个map传来的数据都是有序的(Copy 阶段)。

2)如果reduce端接受的数据量相当小,则直接存储在内存中(缓冲区大小由mapred.job.shuffle.input.buffer.percent属性控制,表示用作此用途的堆空间的百分比),如果数据量超过了该缓冲区大小的一定比例(由mapred.job.shuffle.merge.percent决定),则对数据合并后溢写到磁盘中。

3)随着溢写文件的增多,后台线程会将它们合并成一个更大的有序的文件,这样做是为了给后面的合并节省时间。其实不管在map端还是reduce端,MapReduce都是反复地执行排序,合并操作,可以说:排序是hadoop的灵魂。

4)合并的过程中会产生许多的中间文件(写入磁盘了),但MapReduce会让写入磁盘的数据尽可能地少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到reduce函数。

5)在输入到reduce函数之前,reducer接收到所有映射到这个reducer的map输出后,也是会对key排序,然后开始构造一个key对应的value迭代器。这时就要用到分组,存在默认分组,key相同则分为一组,也可以使用jobjob.setGroupingComparatorClass设置的自定义分组函数类分组,只要这个比较器比较的两个key相同,他们就属于同一个组,它们的value放在一个value迭代器,而这个迭代器的key使用属于同一个组的所有key的第一个key。

第四阶段:Reduce阶段

Reduce阶段就将分组好的<k2,{v2集合}>,进行聚合统计,和map函数一样也是程序员编写的,然后将结果输出到HDFS,每个reduce进程会对应一个输出文件,名称以part-开头。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值