MapReduce是一个分布式运算程序的编程框架,简单的说,就是一个 分布式计算框架,是Hadoop的核心所在。
MR的核心功能,是将用户编写的业务逻辑代码和自身组件相融合,整合成一个完整的分布式运算程序,并发运行在Hadoop集群上。
优点:
缺点:
经典案例:统计一段话中每个单词出现的总次数,其中a~p的结果放在一个文件,q~z的结果放在一个文件里。
MR的计算分为两个阶段:Map阶段和Reduce阶段。
接下来我们以经典案例,来讲解MR的主要工作流程,如图:
1) Map阶段,是任务分配阶段,一般是按照块大小,每个MapTask负责处理一块数据。这个块一般是128M。
这个阶段的MapTask并发实例,完全并发运行,互不相干。
在我们刚说的这个案例里,MapTask中都做了些什么呢?
2) Reduce阶段,就是任务汇总统计阶段。
这一阶段的ReduceTask并发实例也是互不相干,但是它们依赖于Map阶段所有MapTask并发实例的输出。
在这个案例里,因为结果需要有2个文件,所以这里会有2个ReduceTask,一个负责汇总出ap,一个负责汇总出qz,并分别输出至文件。
在一个MR计算过程中,只能包含一个Map阶段和一个Reduce阶段。如果用户的业务逻辑过于复杂,那么可以创建多个MR计算程序,串行计算。这就相当于链式的有向无环图计算了。
一些问题细节:
这些问题都将在后面一一解答。
一个完整的MR程序在分布式运行的时候,会产生三种类型的进程:
MapTask和ReduceTask似乎都是yarnchild,这里仅供参考一下。
WordCount(即WC),这是Hadoop里一个很经典的MR案例,教程后面很多地方在讲解底层原理的时候都会以WC为例做讲解。
官方WordCount的源码在哪儿呢?
大概在Hadoop安装目录的share/hadoop/mapreduce/hadoop-mapreduce-example-xxx.jar
,这里面存储了Hadoop的一些代码案例。
jar包反编译工具:jd-gui。
WC的源码里,核心是三个类:
分工很明确。
另外,这里简单介绍下hadoop中常用的数据序列化类型,后面讲序列化的时候会用到:
Java类型 | Hadoop Writable类型 |
---|---|
Boolean | BooleanWritable |
Byte | ByteWritable |
Int | IntWritable |
Float | FloatWritable |
Long | LongWritable |
Double | DoubleWritable |
String | Text |
Map | MapWritable |
Array | ArrayWritable |
Null | NullWritable |
用户在编写一个完整的MR程序时,需要实现3个部分,即Mapper、Reducer和Driver。
Mapper阶段:
Reducer阶段:
注意,最后一条,Mapper跟Reducer是不一样的。Reducer是每一组相同K的KV对,进一个reduce()。
这个其实很好理解,Reducer阶段就是做汇总的,它是一个数据量减少的过程,其实就是一个把n条具有相同特征的数据,合并成一条数据的过程。
以WC举例,第一句话里字母a出现了3次,第二句话里字母a出现了4次,即mapper会分别输出两个键值对,即(a,3)和(a,4),Reducer则会将这两个键值对输入同一个reduce()进行加和,并最终输出(a,7)。
Driver阶段:
相当于yarn集群的客户端,用于提交整个程序到YARN集群,具体提交的是什么呢?其实是封装了MR程序相关运行参数的一个job对象。所以驱动类里其实就是定义一些运行参数之类的。
一个标准的WordCount需求:统计给定的文本文件中,每一个单词出现的次数。
我们需要针对这个需求,编写对应的Mapper、Reducer和Driver。
这里就不展示代码了,只是展示一下各个类的主要功能。
Mapper负责:
Reducer负责:
Driver阶段: