Hadoop MapReduce 组件详解
MapReduce 是 Hadoop 的核心分布式计算框架 ,用于在大规模集群上并行处理海量数据(TB/PB 级)。它将复杂的分布式计算抽象为两个简单阶段:Map(映射) 和 Reduce(归约),极大简化了大数据编程模型。
一、核心设计思想
1. 分而治之(Divide and Conquer)
- 将大任务拆分为多个小任务并行处理
- 自动处理节点故障、数据本地性、负载均衡等分布式难题
2. 数据本地化(Data Locality)
- 计算任务尽量调度到存储数据的节点上
- 大幅减少网络传输开销
3. 容错机制
- 任务失败自动重试
- 推测执行(Speculative Execution):对慢任务启动备份任务
二、MapReduce 架构演进
▶ Hadoop 1.x 架构(已淘汰)
采用 Master/Slave 模式:
| 组件 | 角色 | 职责 |
|---|---|---|
| JobTracker | Master | 作业调度、任务分配、状态监控 |
| TaskTracker | Slave | 执行具体 Map/Reduce 任务、汇报心跳 |
❌ 缺点:单点故障、扩展性差(最多支持 4000 节点)
▶ Hadoop 2.x+ 架构(YARN 时代)
资源管理与计算框架解耦:
+---------------------+
| Client | ← 提交作业
+----------+----------+
|
+----------v----------+
| ResourceManager (RM) | ← 集群资源总管
+----------+----------+
|
+----------v----------+
| NodeManager (NM) | ← 单节点资源代理
+----------+----------+
|
+----------v----------+
| ApplicationMaster (AM) | ← 每个作业专属管理者
+---------------------+
关键组件说明:
| 组件 | 职责 |
|---|---|
| ResourceManager (RM) | 全局资源调度器,管理所有 NodeManager |
| NodeManager (NM) | 单节点资源监控(CPU/内存)、容器生命周期管理 |
| ApplicationMaster (AM) | 每个 MapReduce 作业独占一个,负责: - 向 RM 申请资源 - 与 NM 通信启动 Task - 监控任务状态 - 处理任务失败重试 |
✅ 优势:支持多计算框架(Spark/Flink 等共用 YARN),扩展性达万级节点
三、MapReduce 作业执行流程(8 步详解)
Client 提交 Job
AM 向 RM 申请 Container
NM 启动 AM
AM 初始化作业
AM 申请 Map Task 资源
NM 启动 Map Task
Map Task 执行 + Shuffle
AM 申请 Reduce Task 资源
NM 启动 Reduce Task
Reduce Task 执行
作业完成
详细步骤:
-
客户端提交作业
- 上传 JAR 包、配置文件到 HDFS
- 向 ResourceManager 提交 Application
-
启动 ApplicationMaster
- RM 分配 Container 启动 AM
- AM 向 RM 注册
-
AM 初始化作业
- 从 HDFS 读取输入分片(Input Splits)
- 计算 Map/Reduce 任务数量
-
运行 Map 任务
-
AM 为每个分片申请 Container
-
NM 启动 Map Task
-
Map 阶段 :
javamap(LongWritable key, Text value, Context context) { // 处理一行数据 → 输出 <word, 1> context.write(new Text(word), new IntWritable(1)); }
-
-
Shuffle 阶段(最复杂!)
- Map 端 :
- 环形缓冲区(默认 100MB)暂存输出
- 溢写(Spill)到磁盘(启用 Combiner 可聚合)
- 合并多个溢写文件
- Reduce 端 :
- 拉取(Fetch)所有 Map 输出
- 合并(Merge)相同 Key 的数据
- 关键优化 :压缩中间数据(
mapreduce.map.output.compress=true)
- Map 端 :
-
运行 Reduce 任务
-
AM 申请 Reduce Container
-
NM 启动 Reduce Task
-
Reduce 阶段 :
javareduce(Text key, Iterable<IntWritable> values, Context context) { int sum = 0; for (IntWritable val : values) sum += val.get(); context.write(key, new IntWritable(sum)); // 输出 <word, total_count> }
-
-
写入结果
- Reduce 输出写入 HDFS(副本数=3)
-
作业清理
- AM 通知 RM 作业完成
- 清理临时文件
四、核心组件深度解析
1. InputFormat(输入格式)
- 作用:定义如何切分输入数据
- 常见实现 :
TextInputFormat:按行读取文本(默认)SequenceFileInputFormat:读取二进制 SequenceFileCombineTextInputFormat:合并小文件(避免过多 Map Task)
2. Mapper / Reducer
- Mapper:处理输入分片 → 生成中间键值对
- Reducer:聚合相同 Key 的值 → 生成最终结果
- 可选组件 :
- Combiner:Map 端预聚合(减少 Shuffle 数据量)
- Partitioner:决定 Map 输出发往哪个 Reduce(默认 HashPartitioner)
3. OutputFormat(输出格式)
- 控制结果写入方式(如
TextOutputFormat,SequenceFileOutputFormat)
五、关键特性与优化点
1. 数据本地性(Data Locality)
- 优先级 :
本地节点 > 同机架 > 跨机架 - 通过 HDFS 块位置信息实现
2. 推测执行(Speculative Execution)
-
检测慢任务(Straggler),启动备份任务
-
配置参数:
xml<property> <name>mapreduce.map.speculative</name> <value>true</value> </property>
3. 内存管理
- Map/Reduce 内存 :通过
mapreduce.map.memory.mb设置 - JVM 重用 :
mapreduce.job.jvm.numtasks减少 JVM 启停开销
4. 压缩优化
| 阶段 | 参数 | 推荐编解码器 |
|---|---|---|
| Map 输出 | mapreduce.map.output.compress |
Snappy(速度快) |
| Job 输出 | mapreduce.output.fileoutputformat.compress |
Gzip(压缩率高) |
六、经典案例:WordCount 执行流程
java
// 输入: "hello world\nhello hadoop"
// Map 阶段:
// (0, "hello world") → [("hello",1), ("world",1)]
// (12, "hello hadoop") → [("hello",1), ("hadoop",1)]
// Shuffle 后:
// ("hello", [1,1])
// ("world", [1])
// ("hadoop", [1])
// Reduce 阶段:
// ("hello", 2)
// ("world", 1)
// ("hadoop", 1)
七、MapReduce vs 新一代引擎
| 特性 | MapReduce | Tez/Spark |
|---|---|---|
| 执行模型 | 批处理(磁盘落盘) | DAG 内存计算 |
| 延迟 | 高(分钟级) | 低(秒级) |
| 适用场景 | ETL、离线分析 | 交互式查询、迭代计算 |
| 容错 | 通过重试 | 血统(Lineage)重建 |
💡 现状 :MapReduce 仍是 Hadoop 生态的稳定基石,但新项目多选用 Spark/Tez。
总结
MapReduce 的伟大之处在于:
- 抽象复杂性 :开发者只需关注
map()和reduce()逻辑 - 自动并行化:框架处理分片、调度、容错
- 水平扩展:轻松扩展至数千节点
尽管新一代引擎性能更优,但理解 MapReduce 仍是掌握大数据技术栈的必经之路------它奠定了分布式计算的理论基础和工程实践范式。