压缩算法怎么选
选压缩算法本质是在压缩比、压缩解压速度、可切分性之间做权衡。snappy 与 lz4 偏快、压缩比中等,适合热数据与高吞吐链路;gzip 通用、压缩比更高,但普通 gzip 文本在 Hadoop 里不可切分;zstd 在压缩比与速度之间比较均衡,近年在冷数据和成本敏感场景使用变多。列存格式(Parquet/ORC)内部按页压缩,切分性问题基本不存在,这也是它比文本格式更省心的原因之一。
基本信息
| 采用位置 | 写入端配置:Spark/MapReduce 参数、表属性、Kafka 生产者参数 |
|---|---|
| 默认值 | Parquet 默认 snappy;Hive ORC 传统默认 ZLIB |
| 关键约束 | 读取端必须能解码,混合引擎集群尤其要注意 |
| 附带影响 | 压缩改变文件体积,也影响读取并行度与 CPU 开销 |
典型使用场景
- 热数据明细层:用 snappy/lz4 换稳定写入与查询速度
- 历史归档与冷数据:用 zstd/gzip 提高压缩比,降低对象存储成本
- 日志文本入湖:gzip 可用但要注意不可切分,或改用可切分方案
- Kafka 消息体压缩:生产者侧设 compression.type,减少网络与磁盘占用
- 跨引擎共享数据:优先选两端都支持的编码器,避免读端解码失败
Spark 写入压缩配置
Spark 写入压缩配置
spark.conf.set('spark.sql.parquet.compression.codec', 'zstd') # 写入端压缩算法
spark.conf.set('parquet.block.size', 128 * 1024 * 1024) # 行组大小,影响单次读取量
df.write.mode('overwrite') \
.option('compression', 'zstd') \ # 显式指定,避免依赖引擎默认值
.partitionBy('dt') \ # 分区列不要选高基数字段
.parquet('s3a://bucket/dwd/orders')
# 验证:读取生成的元数据确认实际编码
# spark.read.parquet('s3a://bucket/dwd/orders').schema算法取舍对照
| 算法 | 压缩比 | 速度 | 文本可切分 | 典型用途 |
|---|---|---|---|---|
| snappy | 中 | 快 | 否 | 列存默认、热数据 |
| lz4 | 中 | 很快 | 否 | 高吞吐链路 |
| zstd | 高 | 较快 | 否 | 冷数据、成本敏感 |
| gzip | 较高 | 中 | 否 | 通用归档与文本 |
| bzip2 | 高 | 慢 | 是 | 离线归档、需可切分的文本 |
普通 gzip 文本在 Hadoop 里不可切分,一个超大文件只能由一个 task 读取,并行度被文件数锁死;列存格式内部按页压缩不受此限制,但把已压缩的 Parquet 再整体打包 gzip 反而会丧失并行读取能力。
同名算法在不同实现下未必完全通用,跨引擎共享数据前先用小文件做一次双向读写验证,比上线后靠报错发现要便宜得多。