前面二十二篇各量了一个方面。这篇把它们放回六个具体场景里,每个场景重新测一遍,给出赢家和适用的前提,以及什么时候什么都不该做。
编码 不压缩 zstd-3 +字典 编码+解码 µs +zstd 字典 µs JSON(orjson) 359.6 288.6 109.1 1.2 3.6 MessagePack 317.8 298.9 112.5 2.4 4.4 Protobuf 242.6 232.7 106.5 4.1 6.5 体积最小:Protobuf + 字典(106.5 字节);不压缩时体积最小:Protobuf(242.6);编码+解码最快(不压缩):JSON(orjson)(1.2 微秒)
不压缩时 Protobuf 小 33%;加了字典后三种编码只差 6%。有字典且追求最小体积用 Protobuf,追求编码解码速度和可读性用 JSON(orjson 编码加解码只要 1.2 微秒)。没有字典的小消息,压缩收益很低(289 对 360 字节)。
组合 字节 占 JSON Lines 压缩耗时 JSON Lines + gzip-9 1460895 20.3% 154ms JSON Lines + zstd-19 1047098 14.5% 1980ms JSON Lines + brotli q11 1015193 14.1% 8094ms Protobuf 整批 + zstd-19 1081117 15.0% 1083ms JSON Lines + xz-9 988040 13.7% 2004ms 体积最小:JSON Lines + xz-9(988040 字节)
写一次、很少读时,选高压缩比的压缩器:xz-9 988040、brotli q11 1015193、zstd-19 1047098,差距在 6% 以内。Protobuf 整批 + zstd-19 反而更大(1081117)。
组合 字节 解压+解析 JSON Lines + lz4 2314121 59.4ms JSON Lines + zstd-3 1331194 59.9ms Protobuf 整批 + lz4 2298068 8.2ms Protobuf 整批 + zstd-3 1378051 10.8ms JSON Lines + zstd-3(orjson 解析) 1331194 23.0ms 读得最快:Protobuf 整批 + lz4(8.2 ms);体积最小:JSON Lines + zstd-3(1331194 字节)
读得多时,看的是解压加解析:Protobuf + lz4 8.2 ms,Protobuf + zstd-3 10.8 ms,JSON(orjson)+ zstd-3 23.0 ms,JSON(标准库)+ zstd-3 59.9 ms。Python 里 JSON 的解析成本远大于解压。
编码 字节 压缩 µs 解压 µs gzip-6 3878 97 11 zstd-3 3898 23 10 brotli q5 3764 153 20 brotli q11 3048 10811 32 现压缩里"体积 × 耗时"(越小越好)的第一名:zstd-3;体积最小:brotli q11
现场压缩的动态响应:zstd-3 的体积乘耗时最小,brotli q11 最小但每页 10.8 ms。静态文件预先压成 q11,动态响应用 gzip-6、zstd-3 或 brotli q4–q5,看客户端的支持。
方式 平均字节 解压 µs/页 原样 13907 0.0 lz4 5861 3.9 zstd-3 4013 10.5 zstd-3 + 字典 2902 12.2 内存最省:zstd-3 + 字典;解压最快(不含原样):lz4
内存是主要成本:zstd-3 加字典每页 2902 字节,原样 13907,省 79%;lz4 解压最快(3.9 微秒/页)。字典要版本化(第 17 篇)。
随机 1 MiB 原 1048576 → zstd-3 1048609( 100.0%) ← 比原文还大 已经 gzip 过的 1 MiB 文本 原 217641 → zstd-3 217656( 100.0%) ← 比原文还大 timeseries 的一行(54 字节) 原 53 → zstd-3 62( 117.0%) ← 比原文还大 50 字节随机串 原 50 → zstd-3 59( 118.0%) ← 比原文还大 products 一条(360 字节) 原 358 → zstd-3 286( 79.9%)
随机、已压缩的数据压不动;几十字节的消息没有字典会变大(117%)。数据模型先于格式(第 20 篇),列式先于格式(第 8 篇),字典先于大量攒批(第 17 篇)。