压缩
Hive 压缩配置:Map 阶段压中间数据,Reduce 阶段压最终结果
| 阶段 | 压什么 | 目的 | 推荐算法 |
|---|---|---|---|
| Map 输出压缩 | Map 任务输出的中间数据 | 减少 Shuffle 阶段网络传输 | Snappy(速度快) |
| Reduce 输出压缩 | 最终写入 HDFS 的结果数据 | 减少存储占用 | Snappy / Gzip(看场景) |
选压缩算法的核心原则:中间数据要快(Snappy),结果数据要省空间(Gzip)。
Map 输出压缩:让 Shuffle 跑得更快
Map 阶段的输出会通过网络传到 Reduce 节点。数据量一大,网络就成了瓶颈。
Map 输出压缩就是把 Map 的结果先压缩再传,减少网络传输量。
配置(在 Hive 会话中执行):
-- 开启中间数据压缩
SET hive.exec.compress.intermediate=true;
-- 指定压缩算法(Snappy 速度最快,推荐)
SET mapreduce.map.output.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
什么时候该开:
- Map 输出数据量大(每个 Map 输出 > 100MB)
- 网络带宽是瓶颈
- 集群 CPU 有余量(压缩消耗 CPU)
什么时候不该开:
- Map 输出数据量小(< 10MB)
- CPU 已经是瓶颈
- 集群 Snappy 没装(会报错)
Reduce 输出压缩:让 HDFS 存得更省
Reduce 输出的数据最终写入 HDFS,存得越久越占空间。
Reduce 输出压缩就是压缩最终结果文件,省存储。
配置:
-- 开启最终输出压缩
SET hive.exec.compress.output=true;
SET mapreduce.output.fileoutputformat.compress=true;
-- 指定压缩算法
SET mapreduce.output.fileoutputformat.compress.codec=org.apache.hadoop.io.compress.SnappyCodec;
-- 压缩类型:BLOCK 比 RECORD 压缩比更高
SET mapreduce.output.fileoutputformat.compress.type=BLOCK;
什么时候该开:
- 结果表数据量大(> 100GB)
- 存储空间紧张
- 数据是历史归档,不频繁读取
什么时候不该开:
- 结果数据量小
- 数据需要频繁读取(解压有额外 CPU 开销)
- 下游系统不支持读压缩文件
常用压缩算法怎么选
| 算法 | 压缩比 | 速度 | 是否可切分 | 用途 |
|---|---|---|---|---|
| Snappy | 中 | 快 | 不可切分 | Map 输出(要速度) |
| Gzip | 高 | 中 | 不可切分 | 结果存储(要空间) |
| LZO | 中 | 快 | 可切分(需索引) | 大文件要并行读 |
| BZIP2 | 最高 | 慢 | 可切分 | 冷数据归档 |
| ZSTD | 高 | 中 | 不可切分 | 新版本支持,比 Gzip 快 |
选型一句话:
- Map 输出无脑 Snappy——速度快,CPU 开销小
- Reduce 输出看场景——日常用 Snappy,归档用 Gzip,超大文件用 LZO
配置持久化:一次配好,不用每次都 set
临时 SET 命令只在当前会话生效。如果想全局生效,写到 hive-site.xml:
<!-- Map 输出压缩 -->
<property>
<name>hive.exec.compress.intermediate</name>
<value>true</value>
</property>
<property>
<name>mapreduce.map.output.compress.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>
<!-- Reduce 输出压缩 -->
<property>
<name>hive.exec.compress.output</name>
<value>true</value>
</property>
<property>
<name>mapreduce.output.fileoutputformat.compress</name>
<value>true</value>
</property>
<property>
<name>mapreduce.output.fileoutputformat.compress.codec</name>
<value>org.apache.hadoop.io.compress.SnappyCodec</value>
</property>
<property>
<name>mapreduce.output.fileoutputformat.compress.type</name>
<value>BLOCK</value>
</property>
验证压缩是否生效
方法1:看任务日志
执行 SQL 后,在 YARN 任务日志里搜:
map output compression codec
output compression codec
能看到 SnappyCodec 就说明配上了。
方法2:看输出文件
-- 查表在 HDFS 上的路径
DESC FORMATTED 表名;
-- 去 HDFS 看文件大小
hdfs dfs -ls -h /user/hive/warehouse/库名.db/表名/
压缩后的文件大小明显小于未压缩的(通常只有 1/3 到 1/4)。
方法3:用 hive -e 跑一条查询,对比时间
不开压缩跑一次
hive -e "SELECT COUNT(*) FROM big_table;"
开了压缩再跑一次
hive -e "SET hive.exec.compress.intermediate=true; SELECT COUNT(*) FROM big_table;"
压缩后 Shuffle 数据量减少,通常会快一些。
常见问题
1. 开启压缩后报错 ClassNotFoundException
Snappy 或 LZO 没装全。检查集群是否支持:
hadoop checknative | grep snappy
如果输出 snappy: true 说明支持
2. 数据量小,压缩后反而变慢
压缩有 CPU 开销。数据量小于 100MB 的时候,压不压区别不大,甚至可能更慢。小表就别开了。
3. Gzip 压缩的文件不能切分,一个 Map 任务处理整个文件?
对,Gzip 文件不可切分。如果你的结果文件有几十 GB,MapReduce 读它的时候只有一个 Map 在干活。解决方案:用 LZO(可切分)或把数据分成多个小文件再压缩。
4. 压缩后的数据 Hive 能直接读吗?
能。Hive 读表的时候会自动根据文件格式判断是否需要解压,你不需要额外配置。