第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。
你如果跑几十个并发压缩线程,内存开销会快速累积。
2.4 指标之间的三角关系
这三者几乎不可能同时最优。
你追求高压缩比,就得忍受慢速度和更高 CPU;你追求极致的速度,压缩比就会很低。
说白了,这是一个取舍问题。
我通常会用一个“三角约束”来形容:
- 如果依赖磁盘 I/O:压缩比优先,但别太慢(有时候走压缩反而省 I/O 时间)
- 如果依赖 CPU/内存:速度优先,用低开销算法
- 如果既想快又想省空间:考虑 zstd 这种可调参数多的算法
2.5 日志压缩的特殊考量
日志和普通文件不一样。日志是文本、小包、实时写。这带来几个特点:
- 逐行压缩效率低 —— 小数据块很难压出高比
- 压缩和解压需要随机访问 —— 你可能只查某几行,不能每次都全量解压
- 写入流量波动大 —— 高峰时 CPU 紧张,算法不能太吃资源
所以我建议你:在日志场景下,压缩比不是第一追求。吞吐和资源消耗才是。
如果你选了一个 CPU 吃满的算法,日志写入一追不上,丢日志比多存点数据更可怕。
2.6 核心指标组合汇总
| 算法 | 压缩速度 | 解压速度 | 压缩比 | CPU开销 | 内存开销 |
|---|---|---|---|---|---|
| lz4 | 极高 | 极高 | 低 | 极低 | 低 |
| zstd (fast) | 高 | 高 | 中 | 低 | 中 |
| gzip (默认) | 中 | 高 | 高 | 中 | 中 |
| zstd (高等级) | 低 | 高 | 很高 | 高 | 高 |
2.7 怎么选?一个简单判断
- 要极致写入吞吐: lz4 或者 snappy
- 要平衡写入和存储: zstd 默认级别或者 fast 模式
- 要极致存储省空间(冷数据): zstd 高等级或 gzip
- 要快速回溯查询: 解压速度优先的算法(lz4 或 zstd)
你想想看,选算法其实就是选你愿意在哪块花资源。
我现在的习惯是:线上日志写入优先用 lz4,冷数据归档用 zstd 级别 3-5。
这样既保证写入不会被拖死,归档文件又足够小。
到这里,你应该能看懂压缩算法的核心指标了。
下一个问题是:这些算法具体怎么实现?它们的内部原理又是什么?
嗯,别急,我们一步步来。先打好指标概念这一关,后面再深入代码和数据结构。