侧边栏壁纸
博主头像
一笑痕

仙人之下我无敌,
仙人之上一换一。

  • 累计撰写 52 篇文章
  • 累计收到 7 条评论

14 种压缩档位实测:两份数据上都最小的是 bzip2

2026-9-16 / 0 评论 / 2 阅读

14 种压缩档位实测:两份数据上都最小的是 bzip2

日志归档用哪个压缩器,答案多半来自习惯,而不是数据。为了把习惯换成数字,生成两份固定种子的数据:12 MiB 的半结构化访问日志,4 MiB 的 JSON 记录,然后让五个压缩器的 14 个档位各跑一遍,统一从 stdin 读、往 stdout 写。脚本存档 tools/verify-compression-bench.py,下面所有数字都是它的输出,两份数据的解压结果都做了 sha256 逐字节校验。

压缩器版本:
  Apple gzip 475
  bzip2, a block-sorting file compressor.  Version 1.0.8, 13-Jul-2019.
  xz (XZ Utils) 5.8.3
  *** Zstandard CLI (64-bit) v1.5.7, by Yann Collet ***
  brotli 1.2.0

数据集 A:12 MiB 访问日志

样例前两行:
  2026-09-02 21:24:10.891 INFO  [req-387480] /static/app.js 989ms 56974 okhttp/4.12
  2026-09-15 21:36:38.512 WARN  [req-260645] /api/order 1785ms 17818 okhttp/4.12

按压缩后体积排序
命令                 压缩后MiB       压缩率       压缩s      解压s
bzip2 -9             2.07     17.2%      0.52     0.18
xz -6                2.36     19.7%      3.47     0.09
xz -6 -T0            2.36     19.7%      3.44     0.09
brotli -q 11         2.37     19.7%     11.71     0.02
zstd -19             2.40     20.0%      3.04     0.01
zstd -19 -T0         2.40     20.0%      3.03     0.01
zstd -9              2.80     23.3%      0.14     0.01
brotli -q 6          2.94     24.5%      0.22     0.02
xz -1                3.01     25.1%      0.16     0.03
gzip -9              3.06     25.5%      0.37     0.01
gzip -6              3.12     26.0%      0.20     0.01
zstd -1              3.32     27.7%      0.02     0.01
brotli -q 1          3.47     29.0%      0.04     0.03
gzip -1              3.83     31.9%      0.05     0.01

全部 14 个档位的解压结果与原文件逐字节一致: True

数据集 B:4 MiB JSON 记录

样例前两行:
  {"ts":1757694675,"event":"page_view","uid":357840,"session":"a4c4c25e","props":{"page":"/p/379","ref":"google","ms":888},"ok":true}
  {"ts":1757459211,"event":"search","uid":316195,"session":"88efc1ba","props":{"page":"/p/255","ref":"google","ms":447},"ok":true}

按压缩后体积排序
命令                 压缩后MiB       压缩率       压缩s      解压s
bzip2 -9             0.50     12.4%      0.20     0.05
brotli -q 11         0.54     13.6%      3.47     0.01
xz -6                0.55     13.7%      0.81     0.03
xz -6 -T0            0.55     13.7%      0.81     0.03
zstd -19             0.56     14.0%      0.73     0.00
zstd -19 -T0         0.56     14.0%      0.74     0.00
zstd -9              0.65     16.2%      0.03     0.00
brotli -q 6          0.68     16.9%      0.04     0.01
gzip -9              0.69     17.2%      0.13     0.00
gzip -6              0.70     17.6%      0.03     0.00
xz -1                0.70     17.6%      0.06     0.02
zstd -1              0.73     18.1%      0.01     0.00
brotli -q 1          0.82     20.5%      0.01     0.01
gzip -1              0.93     23.3%      0.02     0.00

全部 14 个档位的解压结果与原文件逐字节一致: True

体积冠军换了场景,但没换人

bzip2 -9 在两份数据上都排第一:日志压到 17.2%,JSON 压到 12.4%。第二名是 xz -6 和 brotli -q 11 轮流坐,差距很小,日志上差 2.5 个百分点,JSON 上只差 1.2 个点。bzip2 的块排序在重复度高的文本上一直表现很好,这一点和平时听到的「xz 压缩率最高」不太一致,原因大概是那些对比多跑在二进制或者已经压过的数据上。这份样本里它赢了,换成本机安装包之类的输入未必还是这个结果。

三件事的兑换率

这三列数字不可能同时最优,具体摆在一起更清楚:

从 zstd -9 到 zstd -19,日志体积从 23.3% 降到 20.0%,压缩耗时从 0.14 s 涨到 3.04 s,21 倍的时间换 3.3 个百分点的体积。JSON 上同样的跨度是 16.2% 到 14.0%,耗时 0.03 s 涨到 0.73 s,约 24 倍换 2.2 个点。高压缩档位的边际收益很低,除非磁盘真的紧张。

brotli -q 11 值得单独说。它在日志上花 11.71 s 换到 19.7%,和 xz -6 的 3.47 s 拿到同样的体积,慢 3.4 倍;但它解压只要 0.02 s,是全场最快的一组。压一次、解很多次的场景(静态资源预压缩最典型)这笔账是划算的,按天归档每次都要解压的场景反过来。到了 JSON 数据上它的排名还升了两位,反超 xz -6。

解压这一列,bzip2 是唯一的短板:日志上 0.18 s,是 zstd 全部档位(0.01 s)的 18 倍;JSON 上 0.05 s 对 0.00 s。归档数据保留得久、读回次数多的话,省下的那 2 个点体积会被解压时间吃掉大半。

xz -1 在两个数据集上的落差最大,JSON 上掉了两名:17.6% 和 gzip -6 完全打平,耗时却是后者的两倍(0.06 s 对 0.03 s)。LZMA 的快速档在短记录这种形态上没有优势,日志那种长行重复的模式才是它的主场。

多线程在这两个体积上没收益

xz -6 加 -T0 是 3.44 s,不加是 3.47 s;zstd -19 加 -T0 是 3.03 s,不加是 3.04 s。JSON 那边更干脆,0.81 s 对 0.81 s,0.74 s 对 0.73 s,差别在噪声里。12 MiB 和 4 MiB 都太小,多线程的启动和分块开销抵消了并行收益。这条只覆盖这个体积,几百 MiB 以上的文件没有测,别直接外推。

定档

日志按天归档,选 zstd -9:0.14 s 压完,体积 23.3%,解压 0.01 s,三项都很平均。磁盘压力大又不在乎解压慢,选 xz -6 或者 bzip2 -9。临时传输、管道中间环节,选 zstd -1,0.02 s 压完,体积 27.7%。静态资源预压缩选 brotli -q 11,一次性付出 11.71 s,之后每次请求都省。只剩 gzip 能选的场合(对方只认 .gz),那就 gzip -6,别用 gzip -9,0.37 s 只比 0.20 s 多换来 0.06 MiB。

综合下来我的默认档是 zstd -9,理由只能算半条:体积不是最小,但速度和体积都不难看,解压也快,同一份文件要换档位只要改一个数字。

这份数据的边界

两份文件都是脚本生成的合成数据,真实日志的熵比它高,压缩率会更差,但各档位之间的相对顺序通常不会翻盘。所有耗时都是本机单次测量,解压那一列尤其受系统缓存影响,同一份文件连压两次的结果也不会完全一样。内存占用和压缩格式的兼容性没测,这两项在选型里同样重要。

    🤞 分享