MapReduce 不仅仅是一个技术,更是一种编程模型、计算框架和执行引擎。它由 Google 在 2004 年发表的论文《MapReduce: Simplified Data Processing on Large Clusters》中提出,旨在简化大规模数据集(TB/PB 级别)的并行分布式计算。
Apache Hadoop 项目最核心的组件之一就是 Hadoop MapReduce,它是 Google MapReduce 思想的开源实现。
一、核心思想:分而治之
MapReduce 的核心思想非常直观:“分而治之”(Divide and Conquer)。
- 分解(Map):将一个庞大的、复杂的任务分解成许多简单的、可以并行处理的小任务。
- 合并(Reduce):将各个小任务处理的结果进行汇总,得到最终的结果。
这个思想类似于我们现实生活中“统计所有书中某个单词出现次数”的任务:一个人统计一本书太慢,那就把书分给很多人(Map),每个人统计自己那本书,最后有一个人把所有人的统计结果加起来(Reduce)。
二、架构组件与角色
一个典型的 Hadoop MapReduce 集群主要由以下两个核心守护进程组成:
-
ResourceManager (RM) - 资源管理者
- 职责:整个集群资源(CPU、内存等)的全局老大。它负责接收客户端提交的作业,调度和分配资源给各个应用程序。
- 类比:公司的 CEO,负责整个公司的人力资源分配。
-
NodeManager (NM) - 节点管理者
- 职责:每个工作机器(DataNode)上的代理。它负责管理单个节点上的资源和任务执行,向 RM 汇报资源情况并接收来自 RM 的命令。
- 类比:每个部门的经理,管理自己部门的员工,并向 CEO 汇报。
-
ApplicationMaster (AM) - 应用主管(每个作业一个)
- 职责:由 RM 为每个提交的 MapReduce 作业启动的“项目经理”。它负责向 RM 申请资源,与 NM 通信来启动和监控具体的 Map 和 Reduce 任务,并跟踪它们的状态和进度。
- 类比:一个具体项目的项目经理,向 CEO 申请人力,然后管理项目组的成员完成任务。
-
Container - 容器
- 职责:资源的抽象封装(如 2核CPU、4GB内存)。任务(MapTask/ReduceTask)就是在 Container 中运行的。AM 向 RM 申请到 Container,NM 负责启动和管理 Container。
- 类比:一个工位,上面有电脑等办公资源。员工(任务)在工位上工作。
三、核心编程模型:Map 和 Reduce 函数
程序员只需要关注两个核心函数的逻辑,分布式执行的复杂性则由框架处理。
1. Map 阶段 (映射)
- 输入:
(key1, value1)对。例如:(行号, “hello world hello”)。 - 处理:用户自定义的
map函数。读取输入,处理并输出一系列中间(key2, value2)对。 - 输出:
list(key2, value2)。例如:(“hello”, 1), (“world”, 1), (“hello”, 1)。 - 特点:并行、无序。所有 Map 任务之间互不干扰。
2. Shuffle 阶段 (洗牌) - MR 的“心脏”
这是 MapReduce 框架中最复杂、最核心的部分,完全由框架自动完成。它的目的是将 Map 阶段的输出,按照 Key 进行分组和排序,然后分发给对应的 Reduce 任务。
- 分区 (Partitioning):框架会调用分区函数(默认是 Hash),决定每个
(key2, value2)应该被发送到哪个 Reduce 任务处理。例如,hash(key2) % reduce_task_number。确保相同的 Key 一定会去往同一个 Reduce。 - 排序 (Sorting):在每个 Reduce 任务所在的节点,在数据开始处理之前,框架会将从所有 Map 任务拉取过来的数据按照 Key 进行排序。这样,相同 Key 的 Value 就会紧挨在一起。
- 分组 (Grouping):排序后,相同的 Key 对应的所有 Value 就会形成
(key2, list(value2, value2, ...))的形式。
3. Reduce 阶段 (归约)
- 输入:
(key2, list(value2, value2, ...))。例如:(“hello”, [1, 1, 1, ...])。 - 处理:用户自定义的
reduce函数。对传入的某个 Key 的所有 Value 进行归约操作(如求和、求平均、合并等)。 - 输出:
(key2, value3)。例如:(“hello”, 4869)。 - 特点:每个 Key 只会被一个 Reduce 任务处理,但多个 Reduce 任务之间是并行的。
四、任务执行全流程(以 WordCount 为例)
假设有一个 1TB 的文本文件存储在 HDFS 上(被切分成多个 128MB 的 Block),我们要统计所有单词的出现次数。
-
作业提交 (Submit)
- 用户将写好的 WordCount 程序(JAR 包)提交给 ResourceManager。
- RM 找一个空闲的 Container 启动该作业的 ApplicationMaster (AM)。
-
资源申请与分配
- AM 向 RM 申请运行 Map 任务所需的 Container 资源。
- RM 根据调度策略(如 FIFO, Capacity, Fair)和集群资源情况,分配 Container 给 AM。计算向数据移动:RM 会尽量将 Map 任务调度到存储有输入数据块(HDFS Block)的节点上,以避免网络传输开销。
-
Map 阶段执行
- AM 与对应的 NodeManager 通信,在分配到的 Container 中启动 MapTask。
- 每个 MapTask 读取 HDFS 上一个InputSplit(输入分片,通常与 HDFS Block 大小一致)的数据。
- MapTask 逐行处理数据,调用
map函数,输出(word, 1)这样的中间结果。 - 这些中间结果不会立即写入 HDFS(太慢),而是先写入环形内存缓冲区。
-
Shuffle 阶段开始 (Map 端)
- 当内存缓冲区快满时(默认80%),会启动一个溢出(Spill) 过程:
- 分区 & 排序:将缓冲区中的数据按照 Key 和分区进行排序。
- 溢写到磁盘:将排序后的数据分批写入本地磁盘的一个临时文件。
- 当整个 Map 任务完成后,它会将本地磁盘生成的所有临时文件合并(Merge) 成一个大的、已分区且排序好的数据文件。
- 当内存缓冲区快满时(默认80%),会启动一个溢出(Spill) 过程:
-
Shuffle 阶段继续 (Reduce 端)
- ReduceTask 启动后,会通过 HTTP 协议从各个已完成 Map 任务的节点上拉取(Fetch) 属于自己分区的数据。
- 拉取到的数据同样先放在内存中,积攒到一定量后溢出写到磁盘。
- 在所有数据都拉取完毕后,ReduceTask 会将所有磁盘上的临时文件进行一次归并排序(Merge Sort),最终形成一个整体有序的数据文件作为 Reduce 阶段的输入。此时,数据已经是
(key, list(values))的形式。
-
Reduce 阶段执行
- ReduceTask 遍历排序后的数据,对每一个
(key, list(values))调用一次reduce函数。 reduce函数对list(values)求和,得到最终词频(word, count)。- 输出结果直接写入 HDFS 进行永久存储(每个 ReduceTask 输出一个文件)。
- ReduceTask 遍历排序后的数据,对每一个
-
作业完成
- 当所有 MapTask 和 ReduceTask 都成功完成后,AM 向 RM 汇报作业成功。
- RM 清理作业状态,释放资源。
五、MR 的优缺点
优点:
- 易于编程:开发者只需关注业务逻辑(Map和Reduce函数),无需处理分布式、并行、容错等复杂问题。
- 良好的扩展性:计算和存储均可线性扩展。增加机器就能处理更大的数据。
- 高容错性:
- 计算容错:如果某个 Task 失败,AM 会将其调度到另一个节点重新运行。
- 数据容错:输入数据存储在 HDFS 上,有多副本机制。即使一个节点宕机,数据也不会丢失。
- 适合批处理:非常适合对海量数据进行离线、批量的计算。
缺点 (也是催生 Spark/Flink 等新一代引擎的原因):
- 性能瓶颈:磁盘 I/O:
- Map 和 Reduce 阶段之间通过磁盘交换数据(Shuffle 溢写、Merge)。大量的磁盘读写严重拖慢了速度。
- 延迟高:
- 不适合迭代计算(如机器学习算法需要循环迭代)和交互式查询(要求秒级返回)。每一步都需要走完整的 Map-Shuffle-Reduce 流程并落盘。
- 编程模型不够灵活:
- 复杂的业务逻辑(如多表 Join、多个依赖的作业)需要串联多个 MapReduce 作业才能完成,开发难度和运维成本高。
- 实时性差:
- 纯批处理模型,无法处理流式数据。
总结与演进
MapReduce 是大数据领域里程碑式的技术,它用简洁的模型证明了大规模分布式计算的可行性,并奠定了整个生态的基础(HDFS+YARN+MR)。
然而,其基于磁盘的 Shuffle 机制导致的高延迟问题,催生了以 Apache Spark 和 Apache Flink 为代表的新一代计算引擎:
- Spark:提出了 弹性分布式数据集(RDD) 模型,通过内存计算和有向无环图(DAG) 调度器,将多个 MapReduce 阶段组合在一起,尽可能地将中间结果保存在内存中,极大地提升了性能。
- Flink:开创了流处理优先的架构,实现了真正的流批一体,并提供了更高级的 API 和更优秀的性能。
如今,虽然纯粹的 MapReduce 开发已经越来越少(被 Spark/Flink/SQL-on-Hadoop 等取代),但理解其核心思想和架构原理,对于学习任何大数据技术都至关重要,它是整个领域的基石。
1446

被折叠的 条评论
为什么被折叠?



