MapReduce 之概述

工作这段时间已经写过不少 MapReduce Job,但未曾系统地研究过它的运行流程,接下来要花一点时间整理一下。先从概述整个流程开始,随后结合源码简单分析一下各个关键组件。
董西成的《Hadoop 技术内幕:深入解析 MapReduce 架构设计与实现原理》一书中讲到:

回调机制是一种常见的设计模式。它将工作流内的某个功能按照约定的接口暴露给外部使用者,为外部使用者提供数据,或要求外部使用者提供数据。

Hadoop MapReduce 对外提供的 5 个组件(InputFormat、Mapper、Partitioner、Reducer 和 OutputFormat)实际上全部属于回调接口。当用户按照约定实现这几个接口后,MapReduce 运行时环境会自动调用它们。

图 1:MapReduce Overview


图 1 来自《Hadoop 权威指南(第 4 版)》第 7 章,展示了一个 MapReduce Job 的通常流程,简单来说就是:输入文件经 InputFormat 切分成多个 input split,每个 input split 交由一个 Mapper 处理,每个 Mapper 的输出都会先缓存在内存中,缓冲区容量达到一定阈值后会“溢写”(spill)到本地磁盘。注意,Mapper 的输出记录在写入缓冲区之前就会调用 Partitioner 计算出其 partition,而“溢写”之前会按照 partition 和 key 对输出记录进行排序。如果设置了 Combiner,有可能(需要满足一定条件)在排序后的结果上应用一次。这样,每个 Mapper 会“溢写”出多个文件,最后会合并成一个有序的大文件,合并之后还是可能会应用一次 Combiner。Reducer 端会监测每个 Mapper 是否完成,待其完成后从 Mapper 端拉取(fetch)所有属于它的 partition,然后进行多次归并得到整体按 key 排序的结果,输入给 Reducer,Reducer 处理之后调用 OutputFormat 将结果写入 HDFS,至此整个 MapReduce 流程就结束了。

图 2:YARN Overview

现在的 MapReduce Job 一般运行在 YARN 之上,有必要了解一下 YARN 的各个组件是如何协调配合完成 Job 运行的。在此之前,先了解一下 YARN 的架构,如 Hadoop 官方文档提供的图 2 所示,YARN 主要有以下几类核心组件:

  1. Resource Manager(RM):负责整个集群的资源管理和分配,包括处理客户端请求、启动和监控 AM、监控 NM、资源的分配和调度。
  2. Application Master(AM):RM 会为每个 Job 都启动一个 AM,它负责从 RM 协调计算资源,与 NM 配合执行和监控该 Job 的所有 Task。
  3. Node Manager(NM):每个节点上资源和任务的管理器,负责当前节点任务的运行、资源的管理和监控,并向 RM 报告,同时需要执行 RM 和 AM 的命令。
  4. Container:节点上计算资源的抽象,可以看作一个“苦工”(AM 可以看作“包工头”,NM 可以看作“小队长”),负责运行具体的 Task。
图 3:MapReduce on YARN

好了,下面继续讲 MapReduce,图 3 同样来自《Hadoop 权威指南(第 4 版)》第 7 章,展示了 MapReduce Job 在 YARN 上面的运行过程:

  1. Job 提交:调用 Job 对象的 submit() 方法开始提交,创建 JobSubmitter 实例并调用其 submitJobInternal() 方法(step 1),向 RM 申请一个 applicaiton ID(step 2),确认输出路径、计算 input split、将配置、Jar 包、计算出的 input split 元信息放到 HDFS 指定路径下(step 3),最后调用 submitApplication() 方法提交 Job(step 4)。
  2. Job 初始化:RM 收到 Job 提交请求后分配一个 container(step 5a), 然后在其中启动一个主类名为 MRAppMaster 的 AM 进程(step 5b),AM 初始化 Job 并为监控 Task 的运行做准备(step 6),并从 HDFS 指定路径获取 input split 元信息(step 7)。
  3. Task 分配:AM 向 RM 申请运行 Map Task 的 container,等 Map Task 进度到达一定阈值后再申请运行 Reduce Task 的 container(step 8),注意:RM 需要为 Map Task 分配尽量靠近输入数据的 container,而 Reduce Task 没有这样的需求(Reducer 需要从所有 Mapper 拉取输出)。
  4. Task 运行:如果一个 Task 已经被分配了 container,AM 向 NM 发送命令(step 9a),由 NM 启动相应的 contaier(step 9b),然后在 container 中启动一个主类名为 YarnChild 的进程,从 HDFS 拉取配置、Jar 包等资源(step 10),最后开始运行 map 或 reduce Task(step 11)。

有关 MapReduce 流程的简要介绍就到这里,后面开始结合源码分析它的 5 个核心组件:InputFormat、Mapper、Partitioner、Reducer 和 OutputFormat。

0%