bigywater.tech
数据编码与压缩 · 14

zstd 的压缩级别:用更多时间换更小的体积到底怎么换

zstd 的压缩级别到底在换什么?每提高一级,体积小多少、慢多少、多吃多少内存?和 gzip、lz4、snappy、xz、brotli 比又在哪个位置?这篇把级别、内部参数、解压速度、内存和多线程一次量清楚。

21% 对 130 倍
从 zstd 级别 3 到 19,products 体积小的比例与压缩速度变慢的倍数
1737–2028 MiB/s
各级别的解压速度,基本不随压缩级别变化
128.7 MiB
级别 22 压缩 8 MiB 数据时多用的内存(级别 3 是 2.8 MiB)

级别换什么

实测 · 本机执行输出
  --- products JSON Lines,6.9 MiB ---
     级别       压缩后     压缩比      压缩速度      解压速度
     -5   2436466   2.96×    824.4      1681
     -1   1832929   3.94×    676.3      1768
      1   1479666   4.88×    630.4      1788
      3   1331194   5.42×    493.9      1819
      5   1274145   5.66×    211.3      1782
      7   1224789   5.89×    121.0      1062
      9   1208529   5.97×     77.9      2028
     12   1163953   6.20×     44.1      2036
     15   1095849   6.58×     12.7      2209
     17   1074433   6.71×      5.4      1846
     19   1047098   6.89×      3.8      1737
     22   1047069   6.89×      3.2      1739
  --- pages(类 HTML),8.0 MiB ---
     级别       压缩后     压缩比      压缩速度      解压速度
     -5   2813285   2.98×    873.3      2271
     -1   2368714   3.54×    735.4      2477
      1   1812910   4.63×    655.3      2171
      3   1670198   5.02×    419.7      1849
      5   1635572   5.13×    208.1      1800
      7   1593825   5.26×    122.4      1954
      9   1559105   5.38×     90.1      2099
     12   1528567   5.49×     38.3      2106
     15   1512619   5.55×      8.6      1700
     17   1429458   5.87×      4.5      1795
     19   1401606   5.98×      3.3      1633
     22   1401606   5.98×      3.3      1681

级别越高,窗口越大、搜索越深、最小匹配越短、匹配策略越复杂,体积越小,压缩越慢。products 上级别 3 是 5.42×(494 MiB/s),级别 19 是 6.89×(3.8 MiB/s),级别 22 只比 19 再小 29 字节。

内部参数

实测 · 本机执行输出
     级别  strategy windowLog chainLog hashLog searchLog minMatch targetLength
      1         1        19       13      14         1        7            0
      3         2        21       16      17         1        5            0
      5         3        21       18      19         3        5            2
      7         4        21       19      20         4        5            8
      9         5        22       20      21         4        5           16
     12         5        22       22      23         6        5           32
     15         6        22       23      23         6        5           32
     17         7        23       23      22         5        4           64
     19         9        23       24      22         7        3          256
     22         9        27       27      25         9        3          999
  (strategy 编号:1 fast、2 dfast、3 greedy、4 lazy、5 lazy2、6 btlazy2、7 btopt、8 btultra、9 btultra2——这个对应关系我是按 zstd 的头文件记忆写的,没有在本机核对)

zstandard 库的 from_level 给出每个级别的参数:级别 1 的 windowLog 19、searchLog 1;级别 19 的 windowLog 23、searchLog 7、minMatch 3、targetLength 256;级别 22 的 windowLog 27(128 MiB)。第 11 篇里我自己的 LZ77 已经演示过窗口、搜索深度和懒匹配各自的作用。

和其它压缩器的位置

实测 · 本机执行输出
  压缩器                          压缩后     压缩比      压缩速度      解压速度
  zstd-1                   1479666   4.88×    628.8      1611
  zstd-3                   1331194   5.42×    490.6      1783
  zstd-9                   1208529   5.97×     94.2      2016
  zstd-19                  1047098   6.89×      3.9      2088
  gzip(zlib)-1             1803223   4.00×    200.1      1336
  gzip(zlib)-6             1484671   4.86×     73.2      1346
  gzip(zlib)-9             1460895   4.94×     43.1      1124
  lz4 默认                   2314121   3.12×    596.4      4155
  lz4 HC-6                 1666007   4.33×     87.5      4343
  lz4 HC-12                1638242   4.40×     22.2      4159
  snappy                   2511526   2.87×    725.1      1693
  xz 预设 0                  1382936   5.22×     45.4       130
  xz 预设 6                   988040   7.30×      3.6       157
  xz 预设 9                   988040   7.30×      3.6       162
  brotli -q1(命令行)          1588412   4.54×    232.1       344
  brotli -q5(命令行)          1217062   5.93×     73.1       497
  brotli -q9(命令行)          1120363   6.44×     28.7       534
  brotli -q11(命令行)         1012833   7.12×      0.8       511
  (brotli 命令行的速度包含启动进程和读写文件的时间,和库内调用不完全可比;xz 只测了 1 次)

同样的压缩比,zstd 比 gzip 快得多(zstd-1 压缩比 4.88× 且 629 MiB/s,zlib-6 是 4.86× 但 73 MiB/s);lz4 最快的是解压(约 4150 MiB/s),压缩比低;xz 与 brotli-q11 压缩比最高(7.30×、7.12×),但压缩很慢,xz 解压也只有 157 MiB/s。

解压与级别无关

实测 · 本机执行输出
  zstd-1:压缩后 1479666 字节,解压 1788 MiB/s
  zstd-3:压缩后 1331194 字节,解压 1819 MiB/s
  zstd-9:压缩后 1208529 字节,解压 2028 MiB/s
  zstd-19:压缩后 1047098 字节,解压 1737 MiB/s

同一个解压器,解压速度在 1737–2028 MiB/s 之间,不随级别变化——多花的时间只花在压缩一侧。所以适合压缩一次、读取很多次的数据。

内存

实测 · 本机执行输出
  级别  1:窗口 2^19 = 0.5 MiB;压缩峰值内存增量    2.1 MiB(压缩后 1812910 字节);解压峰值内存增量   8.2 MiB
  级别  3:窗口 2^21 = 2.0 MiB;压缩峰值内存增量    2.8 MiB(压缩后 1670198 字节);解压峰值内存增量   8.2 MiB
  级别  9:窗口 2^22 = 4.0 MiB;压缩峰值内存增量    1.7 MiB(压缩后 1559105 字节);解压峰值内存增量   8.1 MiB
  级别 15:窗口 2^22 = 4.0 MiB;压缩峰值内存增量   65.9 MiB(压缩后 1512619 字节);解压峰值内存增量   8.2 MiB
  级别 19:窗口 2^23 = 8.0 MiB;压缩峰值内存增量   81.9 MiB(压缩后 1401606 字节);解压峰值内存增量   8.2 MiB
  级别 22:窗口 2^27 = 128.0 MiB;压缩峰值内存增量  128.7 MiB(压缩后 1401606 字节);解压峰值内存增量   8.2 MiB
  (这是对 8 MiB 输入的测量:输入比窗口小时,实际用到的内存可能比窗口小;输入的 8 MiB 和输出本身也计在内)

高级别的压缩要更大的哈希表和搜索结构:级别 19 多用 81.9 MiB,级别 22 多用 128.7 MiB(窗口 128 MiB)。解压端的内存主要看输出和窗口。窗口大意味着解压端也要有足够内存(见第 16 篇)。

多线程

实测 · 本机执行输出
  级别  3:threads=0 4151340 字节、379.0 MiB/s;threads=4 4147915 字节、756.7 MiB/s(2.0 倍速度,体积-0.08%)
  级别 10:threads=0 3817719 字节、56.2 MiB/s;threads=4 3821356 字节、65.8 MiB/s(1.2 倍速度,体积+0.10%)
  级别 19:threads=0 3411773 字节、2.9 MiB/s;threads=4 3411773 字节、2.5 MiB/s(0.9 倍速度,体积0.00%)

threads=4 在 19.9 MiB 的数据上:级别 3 快 2.0 倍,级别 10 快 1.2 倍,级别 19 没有加速。多线程要把输入切段,输出字节和单线程可能不同,体积差 ±0.1%。

分步演示

zstd 级别
本步的对象

    本文用到的工具与边界

    • 本机 macOS 27 arm64 / Python 3.14.8(系统 Python,自带 compression.zstd)/ zstandard 0.25.0 / lz4 4.4.5 / zstd、lz4、brotli、protoc 命令行(Homebrew);msgpack、protobuf、snappy 等第三方库临时装在临时目录里,用完删除;所有数据都是本机脚本生成的合成数据(固定随机种子),没有使用任何真实网站或用户的数据;计时用 time.perf_counter,取多次中位数,数字每次运行会有小幅抖动。zstandard 0.25.0 的 libzstd 1.5.7;速度是单次或 3 次中位数(级别 15 及以上单次),按原始数据大小算 MiB/s;brotli 用命令行(速度包含进程启动和读写文件);xz 只测一次;内存用独立子进程的 ru_maxrss 增量;各次运行速度有 ±10% 左右的波动(例如 zstd-9 压缩速度在不同次运行里是 77.9 到 94.2 MiB/s)
    • 没有验证:zstd 的 strategy 编号与名字的对应(按记忆写,没有查头文件);--long 模式和 --ultra 的其它参数;负级别以外的“fast”参数调节;更大的输入(GB 级)上各级别的表现;其它 CPU 上的速度;不同 zstd 版本的差别;lz4 与 snappy 的内部格式(见下一篇)
    京ICP备2026067502号-1京公网安备11010502063487号