这一篇文章记录一下hadoop中的分布式运算MapReduce的过程,作为《深入理解大数据》的学习笔记。
上一篇看了HDFS的基本操作,这一篇来看看MapReduce框架。
1.MapReduce基本框架
MapReduce是用来处理大规模数据的一个并行编程框架,采用了对数据“分而治之”的方法。大体上“分而治之”的基本框图结构如下:
MapReduce在总结了典型的大数据处理过程和特征的基础上,提供了一个抽象的模型,是一个离线计算框架。它将计算过程分为了两个阶段,Map和Reduce。其中Map阶段负责并行处理输入数据,Reduce阶段对Map结果进行汇总。其用Map和Reduce函数提供了两个高层的接口。Map和Reduce两个接口由用户去编程实现。
Map的一般处理逻辑是:
一个数据记录以键值对(k1;v1)的方式传入map函数,map函数将处理这些键值对,然后以另一种键值对形式输出一组键值对表示的中间结果[(k2;v2)]。
也就是这样:(k1;v1) ---->map处理---->[(k2;v2)]
Reduce函数的一般处理逻辑是:
对map输出的那组中间结果键值对(k2;[v2]),再进一步进行某种整理计算,最终输出为某种形式的结果键值对[(k3;v3)]。
也就是这样:(k2;[v2])---->reduce处理---->[(k3;v3)]
输入参数变样了是因为在进入reduce前,一般会将具有相同键k2下的所有值v2合并到一个集合中处理:[(k2;v2)]--->(k2;[v2]),也就是Combiner过程。
因此,在经过Map和Reduce的抽象过后,并行结构模型就长这样:
从图中能够方便的看出,大数据通过数据划分,将数据划分成一块一块的,输入各自的Map中进行处理;待所有的Map处理完毕之后,将中间结果输入到Reduce中再进行处理,最终由Reduce处理完后的数据合起来就是我们最终的计算结果了。
上图中也能发现,中间还有一个同步障(Barrier),其作用为要等所有的map节点处理完后才进入reduce,并且这个阶段也负责对map的中间结果进行数据加工整理过程(Aggregation&Shuffle),以便reduce节点可以完全基于本节点上的数据计算最终结果。
不过以上的也还不算是完整的MapReduce编程模型。在上述框架图中,还少了两个步骤Combiner和Partitioner。
Combiner
MapReduce框架提供了一个叫Combiner的对象来对中间结果数据网络传输进行优化。比如在Map处理完输出很多键值对后,某些键值对的键是相同的,在Map节点计算完成的时候,它并不会将相同键的结果合并。而Combiner就可以干这个事情,它能将相同键的值合并,比如有两个键值对的键相同(good,1)和(good,2),便可以合成(good,3)。这样,可以减少需要传输的中间结果数据量,达到网络数据传输优化。因为Map传给Reduce是通过网络来传的。
Combiner程序执行在Map节点完成计算之后、输出中间结果之前。
Partitioner
Partitioner类负责对中间结果进行分区处理,消除数据传入Reduce节点后带来不必要的相关性。比如统计词频的话,将所有主键相同的键值对传输给同一个Reduce节点,以便Reduce节点在不需要访问其他Reduce节点的情况下,一次性对分过来的中间结果进行处理。
这个分区处理是在Map节点输出后、传入Reduce节点之前完成。
添加了Combiner和Partitioner处理后,完整的MapReduce并行编程模型如下图所示:
2.Hadoop系统构架
从逻辑上看,Hadoop系统的基本组成架构包含两个部分:分布式存储和并行计算两部分。
分布式存储(HDFS):Hadoop使用NameNode作为分布式存储的主控节点,用以存储和管理分布式文件系统的元数据,同时使用DataNode作为实际存储大规模数据从节点。
并行计算(MapReduce):Hadoop使用JobTracker作为MapReduce框架的主控节点,用来管理和调度作业的执行,用TaskTracker管理每个计算从节点上任务的执行。
下图为Hadoop系统的基本组成构架。
为了实现Hadoop设计的本地化计算,数据节点DataNode和计算节点TaskTracker应放在同个节点,每个从节点也是同时运行DataNode和TaskTracker,从而让每个TaskTracker尽量处理存储在本地DataNode上的数据。
数据主控节点NameNode与作业执行节点JobTracker可以设置在同一个节点上,也可以考虑负载较高时,而设置在两个节点上。
3.MapReduce执行过程
上图展示了在MapReduce并行计算框架上执行一个用户提交的mapreduce程序的基本过程。
由图中所示,整个过程包括了4个部分:用户程序客户端、JobTracker节点、TaskTracker节点和HDFS存储的部分。整个过程描述:
- 通过JobClient提交用户程序;
- JobClient向JobTracker提交作业执行请求获得一个Job ID;
- JobClient复制作业资源到HDFS中存储;
- JobClient向JobTracker正式提交作业;
- JobTracker接受并调度该作业,并完成初始化准备工作;
- JobTracker查询数据分片信息,构建并准备相应的任务;
- JobTracker启动TaskTracker节点开始执行任务;
- TaskTracker根据分配的具体任务,获取相应作业数据;
- TaskTracker节点开始运行相应的任务;
- TaskTracker执行完任务,输出结果;
- TaskTracker向JobTracker报告分配的任务已完成。
下面再看看作业执行流程和任务执行流程。
以上两幅图分别是作业的执行过程图和任务的执行过程图,其中:
作业的执行流程总体上可以分为三个阶段:准备阶段(PREP)、运行阶段(RUNNING)、结束阶段(FINISHED);并且在各个状态下,作业有可能被客户主动杀死,进入到KILLED状态或在执行中遇到失败,进入到FALED状态。
任务是MapReduce框架进行并行化计算的基本单位,任务是逻辑上的概念,在MapReduce的实现中,分布于JobTracker和TaskTracker上,对应TaskInProgress和TaskTracker.TaskInProgress对象。任务的时序过程如上图所示。
4.MapReduce执行框架的组件和执行流程
下图为MapReduce执行框架的组件和执行流程。
其中的组件分别如下:
- 数据输入格式InputFormat:
它是MapReduce框架中的基础类之一,是一个抽象类,描述了MapReduce作业数据的输入形式和格式。InputFormat可以验证作业数据的输入形式和格式;将输入数据分割为若干个逻辑意义上的InputSplits;提供一个RecordReader。
hadoop提供了功能丰富的InputFormat类,实现从特定数据源或特殊目的的输入要求。常用的有:TextInputFormat、KeyValueInputFormat、NLineInputFormat、CombineFileInputFormat、SequenceFileInputFormat、DBInputFormat等等。
- 输入数据分块InputSplits:
它也是MapReduce框架的基础类之一。一个InputSplit将单独作为一个Mapper的输入,有多少个InputSplit就有多少个Mapper。用户无法自主选定InputSplit的类型,而是在选择某个InputFormat后就决定了对应的InputSplit。InputSplit默认将文件分为64MB的大小,hadoop-site.xml中的mapred.min.split.size参数控制这个大小。
- 数据记录读入RecordReader(RR):
InputSplit定义了一项工作的大小,但是没有定义如何读取数据 。RecordReader即是负责从数据分块中读取数据记录转化为键值对的类。它将数据输出到Mapper类中 。
- Mapper:
每个Mapper对象会生成一个java进程。程序员继承此类,用于实现Map任务。
- Combiner:
上面已提到过,用于合并相同key的键值对,减少partitioner时候的数据通信开销。
- Partitioner:
上面也已提到,为了避免在Reduce计算过程中不同Reduce节点间存在相关性,需要一个Partition过程。
- Sort:
传输到每一个节点上的所有的Reduce函数接收到得Key,value对会被Hadoop自动排序;
- Reducer:
程序员继承此类,用于执行Reduce任务。
- 文件输出格式OutputFormat:
它是用于描述MapReduce作业的数据输出格式和规范的抽象类。写入到HDFS的所有OutputFormat都继承自FileOutputFormat 。其中常用的OutputFormat有:TextOutFormat、SequenceOutFormat、NullOutFormat、DBOutFormat等,太多。
- 数据记录输出RecordWriter:
对于一个文件输出格式,都需要一个对应的数据记录输出RecordWriter,以便系统明确输出结果写入到文件中的具体格式。如TextOutputFormat实现了默认的LineRecordWriter,以“key/value”的形式输出一行结果。
MapReduce的内容蛮多的,上面只是粗略的介绍了一下MapReduce的基本构架,更详细的内容可以参见《深入理解大数据》一书。
下一篇准备看一个官方的小程序wordCount的Java实现,来窥探窥探要写一个mapreduce程序一般需要些什么步骤。