转自https://www.cnblogs.com/mingyueguli/p/10368427.html
1.MapReduce原理
1.1 MapReduce简介
MapReduce是一种分布式计算模型,是Google提出的,主要用于搜索领域,解决海量数据的计算问题。
MR有两个阶段组成:Map和Reduce,用户只需实现map()和reduce()两个函数,即可实现分布式计算
1.2 MapReduce工作原理
MapReduce分为2个过程,分别为Map过程和Reduce过程,如下图所示:
Map端
1)每个输入分片会让一个map任务来处理,默认情况下,以HDFS的一个块的大小(默认为128M)为一个分片,当然我们也可以设置块的大小。map输出的结果会暂且放在一个环形内存缓冲区中(该缓冲区的大小默认为100M,由io.sort.mb属性控制),当该缓冲区快要溢出时(默认为缓冲区大小的80%,由io.sort.spill.percent属性控制),会在本地文件系统中创建一个溢出文件,将该缓冲区中的数据写入这个文件。
2)在写入磁盘之前,线程首先根据reduce任务的数目将数据划分为相同数目的分区,也就是一个reduce任务对应一个分区的数据。这样做是为了避免有些reduce任务分配到大量数据,而有些reduce任务却分到很少数据,甚至没有分到数据的尴尬局面。其实分区就是对数据进行hash的过程。然后对每个分区中的数据进行排序,如果此时设置了Combiner,将排序后的结果进行Combine操作,这样做的目的是让尽可能少的数据写入到磁盘。
3)当map任务输出最后一个记录时,可能会有很多的溢出文件,这时需要将这些文件合并。合并的过程中会不断地进行排序和combine操作,目的有两个:1.尽量减少每次写入磁盘的数据量;2.尽量减少下一复制阶段网络传输的数据量。最后合并成了一个已分区且已排序的文件。为了减少网络传输的数据量,这里可以将数据压缩,只要将mapred.compress.map.out设置为true就可以了。
4)将分区中的数据拷贝给相对应的reduce任务。分区中的数据怎么知道它对应的reduce是哪个呢?其实map任务一直和其父TaskTracker保持联系,而TaskTracker又一直和JobTracker保持心跳,所以JobTracker中保存了整个集群中的宏观信息。只要reduce任务向JobTracker获取对应的map输出位置即可
Reduce端
1)Reduce会接收到不同map任务传来的数据,并且每个map传来的数据都是有序的。如果reduce端接受的数据量相当小,则直接存储在内存中(缓冲区大小由mapred.job.shuffle.input.buffer.percent属性控制,表示用作此用途的堆空间的百分比),当数据量超过该缓冲区大小的一定比例(由mapred.job.shuffle.merge.percent决定),则对数据合并后溢写到磁盘中。
2)随着溢写文件的增多,后台线程会将它们合并成一个更大的有序的文件,这样做是为了给后面的合并节省时间。其实不管在map端还是reduce端,MapReduce都是反复地执行排序,合并操作。排序是hadoop的灵魂。
3)合并的过程中会产生许多的中间文件(写入磁盘),但MapReduce会让写入磁盘的数据尽可能地少,并且最后一次合并的结果并没有写入磁盘,而是直接输入到reduce函数。
2.WordCount数据流程
在WordCount中,Map首先处理的数据经过分片获取输入,以键值对的形式,然后通过Map的切割,切割成一个个单词,然后把每个单词的计数标记为1,并且写到环形内存缓冲区中,排序、合并,写到分区中。
在Reduce段,每个Reduce把每个Map处理的数据中同一个patition的数据拷贝过来,并且经过排序、合并,数据格式类似<Hello,list(1,3,2)>,形成Reudce数据输入。最后才写道HDFS或其他渠道中。
其完整流程如下图:
- 各个reduce也各自并行计算,各自负责处理不同的中间结果数据集合
- 进行reduce处理之前,必须等到所有的map函数做完,因此,在进入reduce前需要有一个同步障(barrier);这个阶段也负责对map的中间结果数据进行收集整理(aggregation & shuffle)处理,以便reduce更有效地计算最终结果
- 最终汇总所有reduce的输出结果即可获得最终结果
3.MapReduce 基本的执行流程
与学习编程语言时采用“hello world”程序作为入门示例程序不同,在大数据处理领域常常使用“wordcount”程序作为入门程序。WordCount 程序是用来统计一段输入的数据中相同单词出现的频率。其基本的执行流程如下图所示:
一个基于MapReduce的WordCount程序主要由一下几个部分组成:
(1)Split
将程序的输入数据进行切分,每一个 split 交给一个 Map Task 执行。split的数量可以自己定义。
(2)Map
输入为一个split中的数据,对split中的数据进行拆分,并以 < key, value> 对的格式保存数据,其中 key 的值为一个单词,value的值固定为 1。如 < I , 1>、< wish, 1> …
(3)Shuffle/Combine/sort
这几个过程在一些简单的MapReduce程序中并不需要我们关注,因为源代码中已经给出了一些默认的Shuffle/Combine/sort处理器,这几个过程的作用分别是:
- Combine:对Map Task产生的结果在本地节点上进行合并、统计等,以减少后续整个集群间的Shuffle过程所需要传输的数据量。
- Shuffle / Sort:将集群中各个Map Task的处理结果在集群间进行传输,排序,数据经过这个阶段之后就作为 Reduce 端的输入。
(4)Reduce
Reduce Task的输入数据其实已经不仅仅是简单的< key, value>对,而是经过排序之后的一系列key值相同的< key, value>对。Reduce Task对其进行统计等处理,产生最终的输出。
4、wordcount代码解析
4.1 API解析
Java的APi的中文版在http://www.matools.com/api/java8可以直接查询
StringTokenizer(String str) :构造一个用来解析 str 的 StringTokenizer 对象。java 默认的分隔符是空格("")、制表符(\t)、换行符(\n)、回车符(\r)。
4.2 代码解读
参考官方网址
http://hadoop.apache.org/docs/r1.0.4/cn/mapred_tutorial.html#%E6%BA%90%E4%BB%A3%E7%A0%81
参考网址
https://blog.youkuaiyun.com/khxu666/article/details/80764994