同系列文章推荐:
Hadoop 上并行应用程序的开发是基于 MapReduce 编程模型的。MapReduce 编程模型的原理是:利用一个输入的 key/value 对集合来产生一个输出的 key/value 对集合。MapReduce 库的用户用两个函数来表达这个计算:Map和 Reduce。
用户自定义的 Map 函数接收一个输入的 key/value 对,然后产生一个中间 key/value 对的集合。MapReduce 把所有具有相同 key 值的 value 集合在一起,然后传递给 Reduce 函数。
用户自定义的 Reduce 函数接收 key 和相关的 value 集合。Reduce 函数合并这些 value 值,形成一个较小的value 集合。一般来说,每次调用 Reduce 函数只产生 0 或 1 个输出的 value 值。通常我们通过-一个迭代器把中间 value 值提供给 Reduce 函数,这样就可以处理无法全部放入内存中的大量的 value 值集合了。
图 1-4 是 MapReduce 的数据流图,体现 MapReduce 处理大数据集的过程。简而言之,这个过程就是将大数据集分解为成百上千个小数据集,每个(或若干个)数据集分别由集群中的-个节点(一般就是-台普通的计算机)进行处理并生成中间结果,然后这些中间结果又由大量的节点合并,形成最终结果。图 1-4 也说明了 MapReduce 框架下并行程序中的两个主要函数:Map、Reduce。在这个结构中,用户需要完成的工作是根据任务编写 Map 和Reduce 两个函数。
编辑切换为居中
图1-4 MapReduce的数据流图
MapReduce 计算模型非常适合在大量计算机组成的大规模集群上并行运行。图 1-4 中的每一个 Map 任务和每一个 Reduce 任务均可以同时运行于一个单独的计算节点上,可想而知,其运算效率是很高的,那么这样的并行计算是如何做到的呢?下面将简单介绍一下其原理。
1 数据分布存储
Hadoop 分布式文件系统(HDFS)由一个名字节点(NameNode)和多个数据节点(DataNode)组成,每个节点都是一台普通的计算机。在使用方式上 HDFS 与我们熟悉的单机文件系统非常类似,利用它可以创建目录,创建、复制、删除文件,并且可以查看文件内容等。但文件在 HDFS 底层被切割成了 Block,这些 Block 分散地存储在不同的 DataNode 上,每个 Block 还可以复制数份数据存储在不同的 DataNode 上,达到容错容灾的目的。NameNode 则是整个 HDFS 的核心,它通过维护一些数据结构来记录每一个文件被切割成了多少个 Block、这些Block 可以从哪些 DataNode 中获得,以及各个 DataNode 的状态等重要信息。
2 分布式并行计算
Hadoop 中有一个作为主控的 JobTracker,用于调度和管理其他的 TaskTracker。JobTracker 可以运行于集群中的任意一台计算机上; TaskTracker 则负责执行任务,它必须运行于 DataNode 上,也就是说 DataNode 既是数据存储节点,也是计算节点。JobTracker 将 Map 任务和 Reduce 任务分发给空闲的 TaskTracker,让这些任务并行运行,并负责监控任务的运行情况。如果某一个 TaskTracker 出了故障,JobTracker 会将其负责的任务转交给另一个空闲的 TaskTracker 重新运行。
3 本地计算
数据存储在哪一台计算机上,就由哪台计算机进行这部分数据的计算,这样可以减少数据在网络上的传输,降低对网络带宽的需求。在 Hadoop 这类基于集群的分布式并行系统中,计算节点可以很方便地扩充,因此它所能够提供的计算能力近乎无限。但是数据需要在不同的计算机之间流动,故而网络带宽变成了瓶颈。“本地计算”是一种最有效的节约网络带宽的手段,业界将此形容为“移动计算比移动数据更经济”。
4 任务粒度
在把原始大数据集切割成小数据集时,通常让小数据集小于或等于 HDFS 中一个 Block 的大小(默认是64MB),这样能够保证一个小数据集是位于一台计算机上的,便于本地计算。假设有 M 个小数据集待处理,就启动 M 个 Map 任务,注意这 M 个 Map 任务分布于N台计算机上,它们将并行运行,Reduce 任务的数量 R 则可由用户指定。
5 数据分割 ( Partition )
把 Map 任务输出的中间结果按 key 的范围划分成 R 份(R 是预先定义的 Reduce 任务的个数),划分时通常使用Hash 函数(如 hash(key) mod R),这样可以保证某一段范围内的 key 一定是由一个 Reduce 任务来处理的,可以简化 Reduce 的过程。
6 数据合并 ( Combine )
在数据分割之前,还可以先对中间结果进行数据合并(Combine),即将中间结果中有相同 key 的 <key, value>对合并成一对。Combine 的过程与 Reduce 的过程类似,在很多情况下可以直接使用 Reduce 函数,但Combine 是作为 Map 任务的一部分、在执行完 Map 函数后紧接着执行的。Combine 能够减少中间结果中<key, value>对的数目,从而降低网络流量。
7 Reduce
Map 任务的中间结果在执行完 Combine 和 Partition 之后,以文件形式存储于本地磁盘上。中间结果文件的位置会通知主控 JobTracker,JobTracker 再通知 Reduce 任务到哪一个 TaskTracker 上去取中间结果。注意,所有的 Map 任务产生的中间结果均按其 key 值通过同一个 Hash 函数划分成了 R 份,R 个 Reduce 任务各自负责一段 key 区间。每个 Reduce 需要向许多个 Map 任务节点取得落在其负责的 key 区间内的中间结果,然后执行Reduce 函数,形成一个最终的结果文件。
8 任务管道
有 R 个 Reduce 任务,就会有 R 个最终结果。很多情况下这 R 个最终结果并不需要合并成一个最终结果,因为这R 个最终结果又可以作为另一个计算任务的输入,开始另一个并行计算任务,这也就形成了任务管道。
参考文档:《Hadoop实战 第2版》
图片:来源《Hadoop实战 第2版》