MapReduce 作业慢?别乱调参数,先找到瓶颈在哪
MapReduce 作业跑得慢,原因可能出在任何地方——CPU、内存、磁盘、网络、数据倾斜、小文件、参数配置……每个环节都可能拖后腿。
但最忌讳的是盲调——看着参数列表挨个改,改完跑一遍,慢就再改。这样不但效率低,还可能越调越慢。
正确的做法是:先定位瓶颈,再针对性调优。
先定位:作业慢,卡在哪个阶段?
YARN UI 是定位瓶颈的第一站。看一个作业的进度:
- Map 阶段慢 → 问题在数据读取或 Map 逻辑
- Shuffle 阶段慢 → 问题在网络传输或数据量
- Reduce 阶段慢 → 问题在数据倾斜或聚合逻辑
再看具体指标:
| 现象 |
可能的原因 |
排查方向 |
| Map 任务进度不均 |
分片大小不均、数据倾斜 |
检查 InputSplit 分布 |
| Reduce 任务有一个特别慢 |
热点 Key 数据倾斜 |
看同一个 Key 的数据量 |
| 磁盘 I/O 满(>80%) |
溢写太频繁 |
调大 io.sort.mb |
| 网络流量大 |
Shuffle 数据量大 |
开启压缩、启用 Combiner |
| CPU 高但作业慢 |
计算逻辑复杂 |
优化代码、减少不必要的序列化 |
定位清楚再动手,比盲目调参数有效十倍。
从投入产出比看:哪些优化最值得做
不是所有优化都值得花时间。按”投入小、收益大”排序:
| 优先级 |
优化手段 |
收益 |
成本 |
| 高 |
开启 Map 输出压缩(Snappy) |
Shuffle 数据量减少 50%+ |
改一行配置 |
| 高 |
启用 Combiner |
Map 输出数据量大幅减少 |
一行代码 |
| 高 |
解决数据倾斜 |
作业时间从几小时降到几十分钟 |
改分区逻辑或加随机后缀 |
| 中 |
调大 io.sort.mb |
溢写次数减少 50%+ |
改一个参数 |
| 中 |
合并小文件(CombineTextInputFormat) |
Map 任务数从几千降到几十 |
改一行代码 |
| 低 |
调大 Reduce 拉取并行度 |
拉取阶段提速 |
改一个参数 |
| 低 |
调整 Map/Reduce 数量 |
提升并行度 |
改一个参数 |
| 有钱就干 |
增加硬件资源(内存、CPU) |
立竿见影 |
加机器/内存 |
实际经验:先做前三个(压缩 + Combiner + 数据倾斜),能解决 80% 的性能问题。
各阶段的针对性优化
输入阶段:减少 Map 任务数
Map 任务太多,调度开销大。任务数 = 数据量 / 分片大小。
- 小文件多 → 用
CombineTextInputFormat 合并分片
- 分片太小 → 调大
split.maxsize,让每个 Map 处理更多数据
- 推荐分片大小:128MB-256MB,一个 Map 任务处理 1-2 分钟的数据量最合适
job.setInputFormatClass(CombineTextInputFormat.class);
CombineTextInputFormat.setMaxInputSplitSize(job, 128 * 1024 * 1024);