第2章:压缩算法基础——压缩比、速度与资源开销

聊日志压缩,你先得看懂压缩算法的三个核心指标。
很多人一上来就比压缩率,谁更“能压”,结果落地时发现解压慢如牛,CPU 吃满,把日志系统活活拖死。
我早期踩过这个坑,后来才明白,这仨指标必须放在一起看。

2.1 压缩比(Compression Ratio)

这个指标很直观。
压缩比 = 原始数据大小 / 压缩后数据大小。
比如 100 MB 压成 10 MB,压缩比就是 10。你存一份日志,只占原来十分之一的空间,省磁盘。

关键认知: 压缩比越高,不一定越好。为什么?因为高压缩比通常意味着慢。你要为 CPU 花时间去换空间。
我在项目中见过有人非要用 gzip -9,结果压缩耗时翻倍,日志写入追不上生成速度,直接丢数据。

算法 典型压缩比(文本日志) 特点
gzip (默认级别) 5 ~ 10 常见,通用
lz4 2 ~ 4 极快,比不高
zstd (默认级别) 6 ~ 15 均衡,可调参数多
避坑指南: 我曾经对一个只有几百字节的日志行反复测试压缩比,结果发现连字典都装不下,压完反而更大。记住,极小数据块不要迷信压缩比。

2.2 压缩 / 解压速度

速度直接决定你的日志系统能扛多大流量。
你想想看,日志是实时写的,如果压缩太慢,日志都来不及写,缓冲区一满,要么丢要么堵。

两个方向都得看:

  • 压缩速度 —— 影响写入吞吐
  • 解压速度 —— 影响读取回溯的速度

有的算法压缩慢但解压快(比如 gzip),适合一次压缩多次读取。
有的算法压缩和解压都快(比如 lz4),适合高频写入和查询。
我个人习惯是:日志写入是常态,先保证压缩速度;但如果你经常要查历史和做分析,解压速度也得硬指标。

2.3 CPU 与内存开销

说实话,这是最容易被人忽略的一块。

CPU 开销: 每次压缩操作都要消耗 CPU 周期。算法越复杂(比如大字典、高压缩级别),CPU 吃得越狠。
如果你的日志服务器本来就在跑业务,CPU 一高,业务响应就变慢。
我记得有一次,我们把日志压缩从 gzip 换成 lz4,CPU 占用从 60% 降到了 15%,写入吞吐反而提高了 2 倍。

内存开销: 算法在运行时需要临时缓冲区、字典、上下文数据。
比如 zstd 的压缩上下文可以到几 MB,而 lz4 只需要不到 1 MB。
你如果跑几十个并发压缩线程,内存开销会快速累积。

注意: 不要只看压缩和解压 API 的内存,还要看算法初始化时的内存分配。我在一个容器化部署的项目里,内存限制只有 256 MB,结果 zstd 的高压缩级别直接 OOM。
压缩算法核心指标权衡图 压缩/解压速度(吞吐量) 压缩比(压缩率) CPU与内存开销 核心权衡关系 速度快 ↔ 压缩比低(如 lz4) 压缩比高 ↔ CPU/内存开销大(如 zstd 高等级) 场景决定优先指标:写入优先选快,归档优先选高压缩比 实时日志 → lz4 / snappy (吞吐优先) 冷存储日志 → zstd / gzip (压缩率优先)

2.4 指标之间的三角关系

这三者几乎不可能同时最优。
你追求高压缩比,就得忍受慢速度和更高 CPU;你追求极致的速度,压缩比就会很低。
说白了,这是一个取舍问题。

我通常会用一个“三角约束”来形容:

  • 如果依赖磁盘 I/O:压缩比优先,但别太慢(有时候走压缩反而省 I/O 时间)
  • 如果依赖 CPU/内存:速度优先,用低开销算法
  • 如果既想快又想省空间:考虑 zstd 这种可调参数多的算法
实践建议: 你开始选算法之前,别先看文档,先测一下自己的生产数据。我在做一个监控系统时,测试发现 lz4 的压缩比只有 2.5,但因为 CPU 省下来了,整体写入延迟降低了 40%。实测数据永远比理论值重要。

2.5 日志压缩的特殊考量

日志和普通文件不一样。日志是文本、小包、实时写。这带来几个特点:

  1. 逐行压缩效率低 —— 小数据块很难压出高比
  2. 压缩和解压需要随机访问 —— 你可能只查某几行,不能每次都全量解压
  3. 写入流量波动大 —— 高峰时 CPU 紧张,算法不能太吃资源

所以我建议你:在日志场景下,压缩比不是第一追求。吞吐和资源消耗才是。
如果你选了一个 CPU 吃满的算法,日志写入一追不上,丢日志比多存点数据更可怕。

我的经验: 我曾经优化过一个日志压缩模块,一开始用的 zstd 级别 10,压缩比漂亮,但线上 CPU 经常飙到 90%。后来喂了测试数据,改成 zstd 级别 1 + 自动字典,效果比默认好了不止一倍。

2.6 核心指标组合汇总

算法 压缩速度 解压速度 压缩比 CPU开销 内存开销
lz4 极高 极高 低 极低 低
zstd (fast) 高 高 中 低 中
gzip (默认) 中 高 高 中 中
zstd (高等级) 低 高 很高 高 高
又一个坑: 内存开销在并发压缩时会被放大。我在一个 8 核机器上,如果同时跑 8 个 zstd 高等级压缩线程,内存占用直接多出 500 MB。你不提前规划,容器可能被 OOM Kill。嗯,这个必须注意。

2.7 怎么选?一个简单判断

  • 要极致写入吞吐: lz4 或者 snappy
  • 要平衡写入和存储: zstd 默认级别或者 fast 模式
  • 要极致存储省空间(冷数据): zstd 高等级或 gzip
  • 要快速回溯查询: 解压速度优先的算法(lz4 或 zstd)

你想想看,选算法其实就是选你愿意在哪块花资源。
我现在的习惯是:线上日志写入优先用 lz4,冷数据归档用 zstd 级别 3-5。
这样既保证写入不会被拖死,归档文件又足够小。

到这里,你应该能看懂压缩算法的核心指标了。
下一个问题是:这些算法具体怎么实现?它们的内部原理又是什么?
嗯,别急,我们一步步来。先打好指标概念这一关,后面再深入代码和数据结构。