MapReduce 设计目标
Hadoop MapReduce 诞生于搜索领域,主要解决搜索引擎面临的海量数据处理扩展性差的问题。它的实现很大程度上借鉴了谷歌 MapReduce 的设计思想,包括:简化编程接口、提高系统容错性等。
Hadoop MapReduce 设计目标,主要有以下几个:
-
易于编程:传统的分布式程序设计非常复杂,需要关注的细节非常多,比如:数据分片、数据传输、节点间通信等,因而设计分布式程序的门槛非常高。 Hadoop 的一个重要设计目标便是简化分布式程序设计,将所有并行程序均需要关注的设计细节抽象成公共模块并交由系统实现,而用户只需专注于自己的应用程序逻辑实现,这样简化了分布式程序设计且提高了开发效率。
-
良好的扩展性:随着公司业务的发展,积累的数据量越来越大,当数据量增加到一定程度后,现有的集群可能已经无法满足其计算能力和存储能力,这时候期望通过添加机器以达到线性扩展集群能力的目的。
-
高容错性:在分布式环境下,随着集群规模的增加,集群中的故障率(包括:磁盘损坏、机器宕机、节点间通信失败等硬件故障和坏数据或者程序 Bug 产生的软件故障)会显著增加,进而导致任务失败和数据丢失的可能性增加。为此,Hadoop 通过计算迁移或者数据迁移等策略提高集群的可用性与容错性。
MapReduce 编程模型
从 MapReduce 的命名可以看出,MapReduce 由两个阶段组成:Map 和 Reduce。用户只需编写 map()
和 reduce()
两个函数,即可完成简单的分布式程序的设计。
map()
函数以 key/value 对作为输入,产生另外一系列 key/value 对作为中间输出写入本地磁盘。MapReduce 框架会自动将这些中间数据按照 key 值进行聚集和分区,且 key 值相同(聚集策略可以重新实现,默认情况下是对 key 值进行哈希取模)的数据被统一交给 reduce() 函数处理。
reduce()
函数以 key 及对应的 value 列表作为输入,合并 key 相同的 value 值后,产生另外一系列 key/value 对作为最终输出写入 HDFS。
以 MapReduce 中的“hello world”程序 —— WordCount 为例介绍:统计输入文件中的每个单词出现的次数。在 MapReduce 中, 可以这样编写(伪代码)
// 其中 Map 部分如下:
// key: 字符串偏移量
// value: 一行字符串内容
map(String key, String value) :
// 将字符串分割成单词
words = SplitIntoTokens(value);
for each word w in words:
EmitIntermediate(w, "1");
// Reduce 部分如下:
// key: 一个单词
// values: 该单词出现的次数列表
reduce(String key, Iterator values):
int result = 0;
for each v in values:
result += StringToInt(v);
Emit(key, IntToString(result));
MapReduce
MapReduce 作业在 Hadoop 中的执行过程如下图所示。(1) 将输入数据切分成若干个输入分片(input split,后面简称 split),并将每个 split 交给一个 Map Task 处理;(2) Map Task 不断地从接收的 split 中读到的字符,并调用 map() 函数处理为 key/value,处理完之后根据 Reduce Task 个数将结果分成若干个分片(partition)写到本地磁盘;(2) 同时,每个 Reduce Task 从每个 Map Task 机器上读取属于自己的那个 partition 作为输入,然后使用基于排序的方法将 key 相同的数据聚集在一起,调用 reduce() 函数处理;(4) 最后将结果输出到文件中。
MapReduce 架构
Hadoop MapReduce 采用了 Master/Slave 架构,主要由以下几个组件组成:Client、JobTracker、TaskTracker 和 Task。
MapReduce架构Client
MapReduce 程序通过 Client 提交到 JobTracker 端。同时,用户可通过 Client 提供的一些接口查看作业运行状态。在 Hadoop 内部用 Job(作业)表示 MapReduce 程序。一个 MapReduce 程序可对应若干个作业,每个作业会被分解成若干个 Map/Reduce Task(任务)。
JobTracker
JobTracker 主要负责资源监控和作业调度。JobTracker 监控所有 TaskTracker 与作业的健康状况,一旦发现失败情况后,其会将相应的任务转移到其他节点。同时,JobTracker 会跟踪任务的执行进度、资源使用量等信息,并将这些信息告诉任务调度器(TaskScheduler),调度器会在资源出现空闲时,选择合适的任务使用这些资源。在 Hadoop 中,任务调度器是一个可插拔的模块,用户可以根据自己的需要设计相应的调度器。
TaskTracker
TaskTracker 会周期性地通过 Heartbeat(心跳)将本节点上资源的使用情况和任务的运行进度汇报给 JobTracker,同时接收 JobTracker 发送过来的命令并执行相应的操作(如启动新任务、杀死任务等)。TaskTracker 使用 slot(任务槽) 等量划分本节点上的资源量。slot 代表计算资源(CPU、 内存等)。一个 Task 获取到一个 slot 后才有机会运行,而 Hadoop 调度器的作用就是将各个 TaskTracker 上的空闲 slot 分配给 Task 使用。slot 分为 Map slot 和 Reduce slot 两种,分别供 Map Task 和 Reduce Task 使用。TaskTracker 通过 slot 数目(可配置参数)限定 Task 的并发度。
Task
Task 分为 Map Task 和 Reduce Task 两种,分别执行 map()
和 reduce()
函数操作,均由 TaskTracker 启动。
HDFS 以固定大小的 block 为基本单位存储数据,而对于 MapReduce 而言,其处理单位是 input split。 split 与 block 的对应关系如下图所示。split 是一个逻辑概念,它只包含一些元数据信息,比如:数据起始位置、数据长度、数据所在节点等。它的划分方法完全由用户自己决定。split 的多少决定了 Map Task 的数目,因为每个 split 会交由一个 Map Task 处理。
InputSplit推荐书籍
《Hadoop技术内幕:深入解析MapReduce架构设计与实现原理》
网友评论