首页/数据/数据工程与 ETL 速查/压缩算法选择:gzip/snappy/zstd 等
管道基础52 条

压缩算法选择:gzip/snappy/zstd 等

压缩在“压缩比、速度、可切分性”之间取舍:snappy/lz4 偏快,gzip 通用,zstd 在压缩比与速度之间较均衡;列存内部按块压缩,切分性影响较小。

压缩算法怎么选

选压缩算法本质是在压缩比、压缩解压速度、可切分性之间做权衡。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 反而会丧失并行读取能力。
同名算法在不同实现下未必完全通用,跨引擎共享数据前先用小文件做一次双向读写验证,比上线后靠报错发现要便宜得多。

易错点

  • 文件后缀与真实压缩格式不一致(例如 zstd 存成 .gz),引擎按错误方式解压,报错或读出乱码
  • 对已压缩的列存再整体 gzip,压缩比几乎不涨却丧失并行读取能力
  • 把 gzip 文本当作可切分文件使用,Spark 分区给再多也只能单 task 读
  • 更换编码器后只验证写入不验证历史文件读取,旧数据在查询时才暴露解码失败

数据来源与参考

  • Apache Parquet 官方文档:Compression
  • Hadoop 官方文档:Compression Codecs 可切分性说明
​‌‌​​‌​​​‌‌​‌‌‌‌​‌‌​​​‌‌​‌‌‌​​‌‌​​‌​‌‌‌​​‌‌‌​​​‌​‌‌​‌​​‌​‌‌‌​​​‌​‌‌​‌​​‌​‌‌​​​‌‌​‌‌‌​‌​​​‌‌​‌‌‌‌​​‌​‌‌‌​​‌‌​​​‌‌​‌‌​‌‌‌‌​‌‌​‌‌​‌