MapReduce(简称MR)最早是由Google公司研究提出的一种面向大规模数据处理的并行计算模型和方法。Google公司设计MapReduce的初衷主要是为了解决其搜索引擎中大规模网页数据的并行化处理。
1.什么是MapReduce
hadoop 的四大组件:
HDFS:分布式存储系统
MapReduce:分布式计算系统
YARN: hadoop 的资源调度系统
Common: 以上三大组件的底层支撑组件,主要提供基础工具包和 RPC 框架等
是的MapReduce就是个计算框架,是一个分布式运算程序的编程框架,是用户开发“基于 hadoop 的数据分析 应用”的核心框架,Mapreduce 核心功能是将用户编写的业务逻辑代码和自带默认组件整合成一个完整的 分布式运算程序,并发运行在一个 hadoop 集群上。
MapReduce擅长处理大数据,它为什么具有这种能力呢?这可由MapReduce的设计思想发觉。MapReduce的思想就是“分而治之”。MR有两个阶段组成:Map和Reduce,用户只需实现map()和reduce()两个函数,即可实现分布式计算。下面就把MapReduce拆开来分析讲解:
1.1Map(映射)
Mapper负责“分”,即把复杂的任务分解为若干个“简单的任务”来处理。“简单的任务”包含三层含义:
一是数据或计算的规模相对原任务要大大缩小;二是就近计算原则,即任务会分配到存放着所需数据的节点上进行计算;三是这些小任务可以并行计算,彼此间几乎没有依赖关系。
1.2Reduce(归约)
Reducer负责对map阶段的结果进行汇总。至于需要多少个Reducer,用户可以根据具体问题,通过在mapred-site.xml配置文件里设置参数mapred.reduce.tasks的值,缺省值为1。
1.3MapReduce解释
一个比较形象的语言解释MapReduce:
我们要数图书馆中的所有书。你数1号书架,我数2号书架。这就是“Map”。我们人越多,数书就更快。
现在我们到一起,把所有人的统计数加在一起。这就是“Reduce”。
2.MapReduce 运行原理
2.1MapReduce运行阶段
2.1.1 MapReduce中的每个map任务可以细分4个阶段:record reader、mapper、combiner和partitioner
map任务的输出被称为中间键和中间值,会被发送到reducer做后续处理。
a)record reader
record reader通过输入格式将输入split解析成记录。record reader的目的只是将输入数据解析成记录,但不负责解析记录本身。它将数据转化为键/值(key/value)对的形式,并传递给mapper处理。通常键是数据在文件中的位置,值是组成记录的数据块。
b)map
在mapper中,用户定义的map代码通过处理record reader解析的每个键/值对来产生0个或多个新的键/值对结果。键/值的选择对MapReduce作业的完成效率来说非常重要。键是数据在reducer中处理时被分组的依据,值是reducer需要分析的数据。
c)combiner
combiner是一个可选的本地reducer,可以在map阶段聚合数据。combiner通过执行用户指定的来自mapper的中间键对map的中间结果做单个map范围内的聚合。例如,一个聚合的计数是每个部分计数的总和,用户可以先将每个中间结果取和,再将中间结果的和相加,从而得到最终结果。在很多情况下,这样可以明显地减少通过网络传输的数据量。在网络上发送一次(hello,3)要比三次(hello,1)节省更多的字节量。通过combiner可以产生特别大的性能提升,并且没有副作用,因此combiner的应用非常广泛。
d)partitioner
partitioner的作用是将mapper(如果使用了combiner的话就是combiner)输出的键/值对拆分为分片(shard),每reducer对应一个分片。默认情况下,partitioner先计算目标的散列值(通常为md5值)。然后,通过reducer个数执行取模运算key.hashCode()%(reducer的个数)。这种方式不仅能够随机地将整个键空间平均分发给每个reducer,同时也能确保不同mapper产生的相同键能被分发至同一个reducer。用户可以定制partitioner的默认行为,并可以使用更高级的模式,如排序。当然,一般情况下是不需要改写partitioner的。对于每个map任务,其分好区的数据最终会写入本地文件系统,等待其各自的reducer拉取。
2.1.2 MapReduce中的reduce任务可以分为4个阶段:混排(shuffle)、排序(sort)、reducer和输出格式(output format)
map任务运行的节点会优先选择在数据所在的节点,因此,一般可以通过在本地机器上进行计算来减少数据的网络传输。
a)混排和排序
reduce任务开始于混排和排序这一步骤。该步骤主要是将所有partitioner写入的输出文件拉取到运行reducer的本地机器上,然后将这些数据按照键排序并写到一个较大的数据列表中。排序的目的是将相同键的记录聚合在一起,这样其所对应的值就可以很方便地在reduce任务中进行迭代处理。这个过程完全不可定制,而且是由框架自动处理的。开发人员只能通过自定义Comparator对象来确定键如何排序和分组。
b)reduce
reducer将已经分好组的数据作为输入,并依次为每个键对应分组执行reduce函数。reduce函数的输入是键以及包含与该键对应的所有值的迭代器。在后文介绍的模式中,我们将看到在这个函数中有很多种处理方法。这些数据可以被聚合、过滤或以多种方式合并。当reduce函数执行完毕后,会将0个或多个键/值对发送到最后的处理步骤——输出格式。和map函数一样,因为reduce函数是业务处理逻辑的核心部分,所以不同作业的reduce函数也是不相同。
c)输出格式
输出格式获取reduce函数输出的最终键/值对,并通过record write将它写入到输出文件中。每条记录的键和值默认通过tab分隔,不同记录通过换行符分隔。虽然一般情况下可以通过自定义实现非常多的输出格式,但是,不管什么格式,最终的结果都将写到HDFS上。
2.2MapReduce运行流程详解
前面详解了MR的各个阶段,这里用通俗的方式来说说运行流程
2.2.1、Map任务处理
读取HDFS中的文件。每一行解析成一个<k,v>。每一个键值对调用一次map函数。 <0,hello you> <10,hello me>
覆盖map(),接收1.1产生的<k,v>,进行处理,转换为新的<k,v>输出。 <hello,1> <you,1> <hello,1> <me,1>
对1.2输出的<k,v>进行分区。默认分为一个区。
对不同分区中的数据进行排序(按照k)、分组。分组指的是相同key的value放到一个集合中。 排序后:<hello,1> <hello,1> <me,1> <you,1> 分组后:<hello,{1,1}><me,{1}><you,{1}>
(可选)对分组后的数据进行归约。
2.2.2、Reduce任务处理
多个map任务的输出,按照不同的分区,通过网络copy到不同的reduce节点上。(shuffle)详见《shuffle过程分析》
对多个map的输出进行合并、排序。覆盖reduce函数,接收的是分组后的数据,实现自己的业务逻辑, <hello,2> <me,1> <you,1>处理后,产生新的<k,v>输出。
对reduce输出的<k,v>写到HDFS中。
3.MapReduce 程序执行流程
自己开发的一个MR应用程序时再hadoop MapReduce框架种如何运行的
(1).客户端提交一个mr的jar包给JobClient(提交方式:hadoop jar ...)
(2).JobClient通过RPC和JobTracker进行通信,返回一个存放jar包的地址(HDFS)和jobId
(3).client将jar包写入到HDFS当中(path = hdfs上的地址 + jobId)
(4).开始提交任务(任务的描述信息,不是jar, 包括jobid,jar存放的位置,配置信息等等)
(5).JobTracker进行初始化任务(放入调度器)
(6).读取HDFS上的要处理的文件,开始计算输入分片,每一个分片对应一个MapperTask
(7).TaskTracker通过心跳机制领取任务(任务的描述信息)
(8).下载所需的jar,配置文件等
(9).TaskTracker启动一个java child子进程,用来执行具体的任务(MapperTask或ReducerTask)
(10).将结果写入到HDFS当中