hadoop MapReduce 详解

首先强调一下,本文是以hadoop 1.x版本为基础整理完成的。

在hadoop中,每个MapReduce任务都被初始化成为一个Job,每一个Job都可以分成两个阶段:Map阶段以及Reduce阶段。Map阶段会接受一个<key,value>的输入,产生一个<key,value>的中间输出,hadoop会把这些key相同的value集合到一起传给reduce函数,reduce会接受一个<key,(list of values)>的输入,处理后输出一个<key,value>。


这里,我们从HDFS中数据的block块开始介绍,数据如何被处理,直到被Reducer Task输出。由上图可知,数据一般处理流程是 mapper task -> combiner -> shuffle -> reduce task。

首先要介绍一下FileInputFormat类:

FileInputFormat是所有以文件作为数据源的InputFormat实现的基类,FileInputFormat保存作为job输入的所有文件,并实现了对输入文件计算splits的方法。至于获得记录的方法是有不同的子类——TextInputFormat进行实现的。


这是它的两个方法。

有三个作用:
1.验证作业的输入是否规范.
2.把输入文件切分成InputSplit
3.提供RecordReader 的实现类,把InputSplit读到Mapper中进行处理.

在执行mapreduce之前,原始数据被分割成若干split,每个split作为一个map任务的输入,在map执行过程中split会被分解成一个个记录(key-value对),map会依次处理每一个记录。 FileInputFormat只划分比HDFS block大的文件,所以FileInputFormat划分的结果是这个文件或者是这个文件中的一部分. 如果一个文件的大小比block小,将不会被划分,这也是Hadoop处理大文件的效率要比处理很多小文件的效率高的原因。

例如:一个1G的文件,会被划分成16个64MB的split,并分配16个map任务处理,而10000个100kb的文件会被10000个map任务处理。   

我们需要重点介绍一下TextInputformat类,TextInputformat类是默认的处理类,处理普通文本文件。一般main函数中我们在job.setInputformatClass([Inputformat class])时,[Inputformat class]一般都是TextInputformat.class,它的特点如下:
1.文件中每一行作为一个记录,他将每一行在文件中的起始偏移量作为key,每一行的内容作为value。
2. 默认以\n或回车键作为一行记录。
3. TextInputFormat继承了FileInputFormat。

除了TextInputformat类,还有其他输入类,如CombineFileInputFormat,相对于大量的小文件来说,hadoop更合适处理少量的大文件,CombineFileInputFormat可以缓解这个问题,它是针对小文件而设计的。KeyValueTextInputFormat:是当输入数据的每一行是两列,并用tab分离的形式的时候,KeyValueTextInputformat处理这种格式的文件非常适合。NLineInputformat:NLineInputformat可以控制在每个split中数据的行数。SequenceFileInputformat:当输入文件格式是sequencefile的时候,要使用SequenceFileInputformat作为输入。这些都不重点介绍,需要的话可以具体查询这些类的使用。

数据经过FileInputFormat处理后,将<key,value>格式的数据交给Mapper Task处理后,再输出输出以<key,value>格式的数据,而每一个map可能会产生大量的输出,combiner的作用就是在map端对输出先做一次合并,以减少传输到reducer的数据量。

接下来介绍一下combiner过程。
combiner最基本是实现本地key的归并,combiner具有类似本地的reduce功能。如果不用combiner,那么,所有的结果都是reduce完成,效率会相对低下。使用combiner,先完成的map会在本地聚合,提升速度。
注意:Combiner的输出是Reducer的输入,如果Combiner是可插拔的,添加Combiner绝不能改变最终的计算结果。所以Combiner只应该用于那种Reduce的输入key/value与输出key/value类型完全一致,且不影响最终结果的场景。比如累加,最大值等。

这里,对combiner进行一个小的总结:

1、是在每一个map task的本地运行,能收到map输出的每一个key的valuelist,所以可以做局部汇总处理
2、因为在map task的本地进行了局部汇总,就会让map端的输出数据量大幅精简,减小shuffle过程的网络IO
3、combiner其实就是一个reducer组件,跟真实的reducer的区别就在于,combiner运行maptask的本地
4、combiner在使用时需要注意,输入输出KV数据类型要跟map和reduce的相应数据类型匹配
5、要注意业务逻辑不能因为combiner的加入而受影响

这个combiner过程并不是必须的,目的只是为了让map端的输出数据量大幅精简,减小shuffle过程的网络IO。

Map的输出会经过一个叫shuffle的过程交给Reduce处理,也有经过sort-merge交给Reduce处理的。在MapReduce过程中,为了让Reduce可以并行处理处理Map结果,必须对Map的输出进行一定的排序与分割,再交给Reduce Task,这个过程就叫shuffle。一言蔽之,shuffle就是对Map端的输出结果进行分区(Partition),排序(sort)以及分割(spill), 然后将属于同一划分的输出合并在一起(merge)并写在磁盘上,同时按照不同的划分结果将结果发送给对应的Reduce(这种对应关系是JobTracker决定的)。Reduce端会将各个Map送来的属于同一划分的输出进行合并(merge),然后对merge的结果进行排序,最后交给Reduce处理。过程如下图所示:

 

Map的输出结果是由collector处理的,所以Map端的shuffle过程包含在collect函数对Map的输出结果处理过程中。 

每个map有一个环形内存缓冲区,用于存储任务的输出。默认大小100MB(io.sort.mb属性),一旦达到阀值0.8(io.sort.spill.percent),一个后台线程把内容写到(这就是spill)磁盘的指定目录(mapred.local.dir)下的新建的一个溢出写文件。写磁盘前,要partition,sort。如果有combiner,combine sort后数据再写磁盘。等最后记录写完,合并全部溢出写文件为一个分区且排序的文件。

Reduce端,shuffle可以分成三个阶段:复制Map输出,合并排序和Reduce处理。

Reducer通过Http方式得到输出文件的分区。TaskTracker为分区文件运行Reduce任务。复制阶段把Map输出复制到Reducer的内存或磁盘。一个Map任务完成,Reduce就开始复制输出。排序阶段合并map输出。然后走Reduce阶段。







  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值