Hadoop并行计算框架核心组件MapReduce

                                                            Hadoop核心组成框架MapReduce框架

MapReduce的工作原理主要是: 通过Map任务读取HDFS中的数据块,这些数据块由Map任务以完全并行的方式处理;然后将Map任务的输出结果进行排序后输入到Reduce任务中;最后Reducer任务将计算的结果输出到HDFS文件系统中。

Map任务中的map()方法和Reduce任务中的reduce()方法需要用户自己实现,二其他操作MapReduce组件已经帮助用户实现了。

通常,MapReduce计算节点和数据存储节点是同一个节点,即MapReduce框架和HDFS文件系统运行在同一组节点上。这样的配置可以使MapReducer框架在有数据的节点上高效地调度任务,避免过度消耗集群的网络带宽。

MapReduce是Hadoop的一个核心组成框架,使用该框架编写的应用程序能够以一种可靠的,容错的方式并行处理大型集群(数千个节点)上的大量数据(TB级别以上),也可以对大数据进行加工,挖掘和优化等处理。

一个MapReducer任务主要包括两部分: Map任务和Reduce任务。Map任务负责对数据的获取,分割与处理,器核心执行方法为map()方法;Reduce任务负责对Map任务的结果进行汇总,器核心执行方法为reducer()方法。MapReduce将并行计算过程高度抽象到了map()方法和reduce()方法中,程序员只负责这两个方法的编写工作,而并行程序中的其他复杂问题(如分布式存储,工作调度,负载均衡,容错处理等)均可由MapReduce框架代为处理,程序员完全不用操心。

设计思想

MapReduce的设计思想是,从HDFS中获得输入数据,将输入的一个大的数据集分割成多个小数据集,然后并行计算这些小数据集,最后将每个小数据集的结果进行汇总,得到最终的计算结果,并将结果输出到HDFS中,如下图所示:

                                                   

在MapReduce并行计算中,对大数据集分割后的小数据集的计算,采用的是map()方法,各个map()方法对输入的数据进行并行处理,对不同的输入数据产生不同的输出结果;而对小数据集最终结果的合并,采用的是reduce()方法,各个reduce()方法也各自进行并行计算,各自负责处理不同的数据集合。但是在reduce()方法处理之前,必须等到map()方法处理完毕,因此在数据进入到reduce()方法之前需要有一个中间阶段,负责对map()方法的输出结果进行整理,将整理后的结果输入到reduce()方法,这个过程称为Shuffle阶段。

此外,在进行MapReduce计算时,有时候需要把最终的数据输出到不同的文件中,比如,按照省份划分的话,需要把同一省份的数据输出到一个文件中;按照性别划分的话,需要把同一性别的数据划分到同一个文件中。我们知道,最终的输出数据来自于Reduce任务,如果得到多个文件,意味着有同样数据量的Reduce任务在运行。而Reduce任务的数据来自于Map任务,也就是说,Map任务要进行数据划分,对于不同的数据分配给不同的Reduce任务执行。Map任务划分数据的过程就称作分区(Partition),从编程的角度来看,可以对上图的流程进行细化,如下图:

                                      

 

 

总结来说,MapReduce利用了分而治之的思想,将数据分布式并行处理,然后进行结果的汇总。举个例子,有一堆扑克牌,现在需要把里面的花面都分开,而且统计每一种花色的数据。一个人清点可能耗时4分钟,如果利用MapReduce的思想,把扑克牌分成4份,每个人对自己的那一份进行清点,4个人都清点完成之后把各自的相同花色放到一起并清点每种花色的数量,那么这样可能只会耗时1分钟。在这个过程中,每个人就相当于一个map()方法,把各自的相同花色放到一起的过程就是Partition,最后清点每一种花色的数量的过程就是reduce()方法。

 

 

 

任务流程

MapReduce程序运行于YARN之上,使用YARN进行集群资源管理和调度。每个MapReduce应用程序会在YARN中产生一个名为”MRAppMaster”的进程,该进程是MapReduce的ApplicationMaster实现,它具有YARN中ApplicationMaster角色的所有功能,包括管理整个MapReduce应用程序的生命周期,任务资源申请,Container启动与释放等。

客户端将MapReduce应用(jar,可执行文件等)和配置信息提交给YARN集群的ResourceManager,ResourceManager负责将应用程序和配置信息分发给NodeManager,调度和监控任务,向客户端提供状态和诊断信息等.

下图为MapReduce应用程序在YARN中的执行流程。

       

                                          

 

 

        (1).客户端提交MapReduce应用程序到ResourceManager。

 

         (2).ResourceManager分配用于MRAppMaster的Container,然后与NodeManager通信,要求它在该Container中启动MRAppMaster。MRAppMaster启动后,它将负责此应用程序的整个声明周期。

 

         (3).MRAppMaster向ResourceManager注册(注册后客户端可以通过ResourceManager查看应用程序的运行状态)并请求运行应用程序各个Task所需Container(资源请求是对一些Container的请求)。如果符合条件,ResourceManager会分配给MRAppMaster所需的Container。

         (4).MRAppMaster请求NodeManager使用这些Container来运行应用程序的相应Task(即将Task发布到指定的Container中运行)。

   此外,各个运行中的Task会通过RPC协议向MRAppMaster汇报自己的状态和进度,这样一旦某个Task运行失败时,MRAppMaster可以对其重新启动。当应用程序运行完成时,MRAppMaster会向ResourceManager申请注销自己。

 

工作原理:


MapReduce计算模型主要由三个阶段组成: Map阶段,Shuffle阶段,Reduce阶段,如下图所示

                               

 

Map阶段的工作原理如下:

将输入的多个分片(Split)由Map任务以完全并行的方式处理。每个分片由一个Map任务来处理。默认情况下,输入分片的大小与HDFS中数据块(Block)的大小相同,即文件有多少个数据块就有多少个输入分片,也就会有多少个Map任务,从而可以通过调整HDFS数据块的大小间接改变Map任务的数量。

每个Map任务对输入分片中的记录按照一定的规则解析成多个<key,value>对,默认将文件中的每一行解析成一个<key,value>对,可以为每一行的起始位置,value为本行的文本内容,然后将解析出的所有<key,value>对分别输入到map()方法中进行处理(map()方法一次只处理一个<key,value>对)。map()方法将处理结果仍然是以<key,value>对的形式进行输出。

由于频繁的磁盘(I/O)会降低效率,因此Map任务输出的<key,value>对会首先存储在Map任务所在的节点(不同的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)的临时文件中。

在数据溢写到磁盘之前,会对数据进行分区(Partition)。分区的数量与设置的Reduce任务的数量相同(默认Reduce任务的数量为1,可以在编写MapReduce程序时对其修改)。这样每个Reduce任务会处理一个分区的数据,可以防止有的Reduce任务分配的数据量太大,而有的Reduce任务分配的数据量太小,从而可以负载均衡,避免数据倾斜。数据分区的划分规则为:取<key,value>对中key的hashCode值,然后除以Reduce任务数量后取余数,余数则是分区编号,分区编号一致的<key,value>对则属于同一个分区。因此,key值相同的<key,value>对一定属于同一个分区,但是同一个分区中可能有多个key值不同的<key,value>对。由于默认Reduce任务的数量为1,而任何数字除以1的余数总是0,因此分区编号从0开始。

MapReduce提供的默认分区类为HashPartitioner,该类的核心代码如下:

public  class  HashPartitioner<K2,V2>  implements  Partitioner<K2,V2>{

       /** 获取分区编号**/

       public int getPartition(k2 key,v2 value,int numReduceTasks) {

           Return (key.hashCode() & Integer.MAX_VALUE) % numReduceTasks;           

   }

}

getPartition()方法有三个参数,前两个参数指的是<key,value>对中的key和vlaue,第三个参数指的是Reduce任务的数量,默认值为1。由于一个Reduce任务会向HDFS中输出一个结果文件,而有时候需要根据自身的业务,将不同key值的结果数据输出到不同的文件中。例如,需要统计各个部门的年销售总额,每一个部门单独输出一个结果文件,这个时候就可以自定义分区。

分区后,会对同一个分区中的<key,value>对按照key进行排序,默认升序。

Reduce阶段的工作原理如下:

Reduce阶段首先会对Map阶段的输出结果按照分区进行再一次合并,将同一分区的<key,value>对合并到一起,然后按照key对分区中的<key,value>对进行排序。

每个分区会将排序后的<key,value>对按照key进行分组,key相同的<key,value>对将合并为<key,value-list>对,最终每个分区形成多个<key,value-list>对。例如,key中存储的是用户ID,则同一个用户的<key,value>对会合并到一起。

排序并分组后的分区数据会输入到reduce()方法中进行处理,reduce()方法一次只能处理一个<key,value-list>对。

最后,reduce()方法将处理结果仍然以<key,value-list>对的形式通过context.write(key,value)进行输出。

Shuffle阶段所处的位置是Map任务输出后,Reduce任务接收之前。Shuffle阶段主要是将Map任务的无规则输出形成一定的有规则数据,以便Reduce任务进行处理。

总结来说,MapReduce的工作原理主要是: 通过Map任务读取HDFS中的数据块,这些数据块由Map任务以完全并行的方式处理;然后将Map任务的输出进行排序后输入到Reduce任务中;最后Reduce任务将计算的结果输出到HDFS文件中。

Map任务中的map()方法和Reduce任务中的reduce()方法需要用户自己实现,而其他操作MapReduce已经帮用户实现了。

通常,MapReduce计算节点和数据存储节点是同一个节点,即MapReduce框架和HDFS文件系统运行在同一组节点上。这样的配置可以使MapReduce框架在有数据的节点上高效地调度任务,避免过度消耗集群的网络带宽。

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值