1、输入分片(Input Split):

在进行map计算之前,mapreduce会根据输入文件计算输入分片,每个输入分片针对一个map任务,输入分片存储的并非数据本身,而是一个分片长度和一个记录数据位置的数据。输入分片往往和hdfs的block关系密切,假如我们设定hdfs块的大小是64mb,如果我们输入三个文件,大小分别是3mb、65mb和127mb,那么mapreduce会把3mb文件作为一个输入分片,65mb分成两个输入分片,127mb分成两个输入分片。

2、map阶段:

3、combiner阶段:combiner其实也是一种reduce操作,本地化的预处理,比如简单合并重复key在值

4、shuffle阶段:将map的输出作为reduce的输入的过程就是shuffle。shuffle一开始就是map阶段做输出操作,一般mapreduce计算的都是海量数据,map输出的时候不可能吧所有文件都放到内存操作,因此map写入磁盘的过程十分的复杂,更何况map输出时候要对结果进行排序,内存开销是 很大的,map在做输出时候会在内存里开启一个缓冲区,默认大小是100mb,并且在配置文件里为缓冲区设定了一个阈值,默认是0.8,同时map还会为输出操作启动一个守护线程,如果缓冲区数据达到阈值,守护线程就会把内容写到磁盘上,这个过程叫做spill,另外20%的内存可以继续写入数据,写入磁盘和写入内存操作是互不干扰的,如果缓存区被撑爆了,那么map就会阻塞写入内存的操作,让写入磁盘操作完成后在继续执行写入内存操作,写入磁盘前会有个排序操作,这个实在写入磁盘操作时候进行,不是在写入内存时候进行的,如果定义了combiner函数,排序钱还会执行combiner操作。

每次spill操作也就是写入磁盘操作的时候会写一个溢出文件,也就是说在坐map输出有几次spill就会产生多少个溢出文件,等map输出全部做完,map会合并这些输出文件。这个过程里还会有一个partition操作,其实partition操作和map阶段的输入分片很想,一个partition对应一个reduce作业,partition因此就是reduce的输入分片,根据实际业务类型或者为了更好的reduce负载均衡要求进行,合理的partition的设置可以提高reduce的效率。

到了reduce阶段就是合并map输出文件,partitioner会找到对应的map输出文件,然后进行复制操作,复制操作时reduce会开启几个复制线程,默认5个,这个复制过程和map写入磁盘过程类似,也有阈值和内存大小,复制时候reduce还会进行排序操作和合并文件操作,完事后就会进行reduce计算了。

5.reduce阶段:计算完成后,把结果写入hdfs上

 

map task 读取数据

map业务处理

对key进行sort排序,grouping分组将相同key的value合并分组输出,进行一个combiner归约操作,本地化的reduce预处理,以减小shuffle,reducer的工作量。

reduce task会通过网络将各个数据收集进行reduce处理,最后将数据保存会输出,结束job

 

shuffle

shuffle描述着数据从map task 输出到reduce task输入的这段过程。

hadoop的集群环境,大部分的map task和reduce task是执行在不同的节点上的,那么reduce就要取map的输出结果。那么集群中运行多个job是,task的正常执行会对集群内部的网络资源消耗严重。虽说这种消耗是正常的,是不可避免的,但是,我们可以采取措施尽可能的减少不必要的网络资源消耗。另一方面,每个节点的内部,相比于内存,磁盘IO对Job完成时间的影响相当的大。

所以:从以上分析,shuffle过程的基本要求:

1.完整地从map task端拉取数据到reduce task 端

2.在拉取数据的过程中,尽可能地减少网络资源的消耗

3.尽可能地减少磁盘IO对task执行效率的影响

那么,shuffle的设计目的就要满足以下条件:

1.保证拉取数据的完整性

2.尽可能地减少拉取数据的数据量

3.尽可能地使用节点的内存而不是磁盘

一、map阶段

map节点执行map task任务生成map的输出结果

shuffle的工作内容:

从运算效率的出发点,map输出结果优先存储在map节点的内存中。每个map task 都有一个内存缓冲区,存储着map的输出节点,当缓冲区达到阈值时(0.8),需要讲缓冲区中的数据以一个临时文件的方式存到磁盘(spill),当整个map task结束后再对磁盘中这个map task所产生的所有临时文件做合并,生成最终的输出文件。最后,等待reduce task来拉取数据。当然,如果map task的结果不大,能够完全存储到内存缓冲区,且未达到内存缓冲区的阈值,那么就不会有写临时文件到磁盘的操作,也不会有后面的合并。

二、reduce阶段:

当mapreduce任务提交后,reduce task就不断通过RPC从JobTracker那里获取map task是否完成的信息,如果获知某台TaskTracker上的map task执行完成,shuffle的后半段过程就开始启动。其实呢,reduce task在执行之前的工作就是:不断的拉取当前job里每个map task的最终结果,并对不同地方拉取过来的数据不断地做merge。

reduce阶段分三个步骤:

抓取、合并、排序

1、reduce任务会创建并行的抓取线程(fetcher)负责从完成的map任务重获取结果文件,是否完成通过rpc心跳监听,通过http协议抓取,默认是5个抓取线程,可调,为了是整体并行,在map任务量大,分区多的时候,抓取线程调大。

2、抓取拉过来的数据会先保存在内存中,如果内存过大也移除,不可见,不可调,但是单位是每个merge文件,不会切分数据;每个merge文件都会被封装成一个segment的对象,这个对象控制着这个merge文件的读取记录操作。

3、这中segment对象会放到一个内存队列中MergerQueue,对内存和磁盘上的数据分别进行合并,内存中的merge对应的segment直接合并,磁盘中的合并与一个叫做合并因子的factor有关。

4、排序问题

MergerQueue继承轮换排序的接口,每一个segment 是排好序的,而且按照key的值大小逻辑(和真的大小没关系);每一个segment的第一个key都是逻辑最小,而所有的segment的排序是按照第一个key大小排序的,最小的在前面,这种逻辑总能保证第一个segment的第一个key值是所有key的逻辑最小文件合并之后,最终交给reduce函数计算的,是MergeQueue队列,每次计算的提取数据逻辑都是提取第一个segment的第一个key和value数据,一旦segment被调用了提取key的方法,MergeQueue队列将会整体重新按照最小key对segment排序,最终形成整体有序的计算结果;

//todo 通过实际操作 继续理解