MapReduce 数据压缩:用 CPU 换 IO,这笔账怎么算?
数据压缩是 MapReduce 性能优化的”常规武器”——减少磁盘写入、减少网络传输、节省存储空间。但压缩不是白给的,它消耗 CPU。
核心逻辑就一句话:用 CPU 换 IO。
- 如果作业瓶颈在 IO(磁盘读写在等)→ 压缩能提速
- 如果作业瓶颈在 CPU(CPU 已经跑满)→ 压缩会拖慢
压缩解决什么问题?
MapReduce 作业里,数据到处流动:
- Map 输出 → 写到本地磁盘(Map 端 Shuffle)
- Map 输出 → 传给 Reduce(网络传输)
- Reduce 输出 → 写到 HDFS(结果存储)
这些环节都有 IO 和网络开销。压缩了,数据变小,IO 和网络就省了。代价是压缩和解压缩需要 CPU 算力。
什么场景该压?
压缩的本质是 用 CPU 时间换取 IO 效率,选择是否压缩需遵循以下原则:
- IO 密集型作业(如日志分析、数据清洗):优先启用压缩(IO 瓶颈更突出);
- 运算密集型作业(如复杂统计、机器学习):谨慎使用压缩(避免 CPU 成为新瓶颈);
- 中间数据 / 结果数据:中间数据(Shuffle 阶段)和长期存储的结果数据建议压缩。
常用压缩格式对比与选型
MapReduce 支持多种压缩格式,不同格式在压缩率、速度和可切分性上各有优劣,需根据场景选择。
压缩格式核心特性对比
| 压缩格式 | Hadoop 自带 | 算法 | 文件扩展名 | 可切分性 | 压缩率 | 压缩速度 | 解压缩速度 | 适用场景 |
|---|---|---|---|---|---|---|---|---|
| DEFLATE | 是 | DEFLATE | .deflate | 否 | 中 | 中 | 中 | 通用中间数据压缩 |
| Gzip | 是 | DEFLATE | .gz | 否 | 高 | 中 | 中 | 结果数据存储(压缩率优先) |
| Bzip2 | 是 | Bzip2 | .bz2 | 是 | 最高 | 慢 | 中 | 冷数据归档(压缩率优先,不计较速度) |
| LZO | 否(需安装) | LZO | .lzo | 是(需建索引) | 中 | 快 | 快 | 大文件中间数据(需切分场景) |
| Snappy | 否(需安装) | Snappy | .snappy | 否 | 中低 | 最快 | 最快 | 实时 / 高吞吐场景(速度优先) |
选型就三条:
- 要速度 → Snappy(Shuffle 中间数据首选)
- 要空间 → Bzip2 或 Gzip(结果存储、冷归档)
- 要大文件 + 要并行 → LZO(单文件 > 1GB,需要切分处理)
实际生产中最常用的组合:
- Map 输出(Shuffle)→ Snappy:速度快,网络传输省 50%+
- Reduce 输出(结果)→ Gzip:压缩率不错,Hadoop 自带,不用额外装
怎么配?三个阶段的压缩配置
阶段1:输入压缩——自动解压,啥都不用配
Hadoop 通过文件扩展名自动识别压缩格式:
.gz→ Gzip.bz2→ Bzip2.lzo→ LZO.snappy→ Snappy
只要是这些后缀,MapReduce 读的时候自动解压,不需要额外配置。
阶段2:Map 输出压缩——Shuffle 阶段,最推荐开启
1 | <!-- mapred-site.xml --> |
或者在代码里配置:
1 | conf.setBoolean("mapreduce.map.output.compress", true); |
阶段3:Reduce 输出压缩——结果存到 HDFS,省空间
1 | <!-- 启用 Reduce 输出压缩 --> |
或者在代码里配置:
1 | // 启用 Reduce 输出压缩 |
两个特殊格式的说明
可切分(Splittable)为什么重要?
默认情况下,一个文件对应一个 InputSplit,然后一个 Map 任务处理。
- 如果文件是 不可切分 的压缩格式(Gzip、Snappy),一个 10GB 的 Gzip 文件只能由一个 Map 任务处理,完全失去并行性
- 如果文件是 可切分 的压缩格式(Bzip2、LZO),文件可以按 Block 切开,多个 Map 并行处理
结论:大文件 > 1GB,用 Bzip2 或 LZO(带索引),否则单个 Map 任务会卡死。
LZO 的”索引”是什么?
LZO 本身不可切分,但可以通过建索引实现切分:
1 | # 给 LZO 文件建索引 |
建完索引后,Hadoop 就能按 Block 切分 LZO 文件并行处理。
Snappy 和 LZO 需要额外安装
Hadoop 自带的压缩格式只有:DEFLATE、Gzip、Bzip2。
Snappy 和 LZO 需要额外安装。
Snappy 安装(每个节点都要装):
1 | # 1. 下载并安装 Snappy 库 |
LZO 安装:
1 | # 1. 安装 LZO 库 |
检查 Hadoop 支持哪些压缩格式:
1 | hadoop checknative |
怎么判断压缩生效了?
1. 看日志
作业运行日志里会有 “Compression” 相关输出。如果配置了 Map 输出压缩,能看到:
1 | Map output compression: true |
2. 看文件大小和扩展名
Reduce 输出文件如果配置了 Gzip 压缩,生成的文件后缀是 .gz,大小明显小于未压缩的版本。
3. 看 Shuffle 传输量
在 YARN UI 里看作业的 “Shuffle Bytes”——如果压缩生效,这个数值会显著减少。
几个常见问题
1. 压缩反而更慢了?
可能是两个原因:
- CPU 已经是瓶颈(加压缩只会更慢)
- 用了 Bzip2 这种高压缩率的格式(算法本身就慢)
解决: 换 Snappy 或 LZO,把”高压缩率”换成”高速度”。
2. Map 输出压缩用什么格式?
无脑 Snappy。 速度快、CPU 开销小,Shuffle 网络传输省 50%+。
3. 结果存储用什么格式?
- 长期存储(归档)→ Bzip2(压得最小)
- 日常存储 → Gzip(压缩率好,Hadoop 自带)
- 后续还要做 MapReduce 处理且文件很大 → LZO(可切分)
4. Gzip 文件太大,只有一个 Map 处理怎么解决?
没有办法。Gzip 不可切分。要么换格式(LZO/Bzip2),要么在数据源头就切成多个 Gzip 文件。