知其然,知其所以然
数据编码与压缩 2026-10-12

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

实测 zstd 级别 -5 到 22:从级别 3 到 19 体积小 21% 但压缩慢 130 倍;解压速度与级别无关(约 1700–2000 MiB/s);级别 22 需要 128.7 MiB 压缩内存;和 gzip、lz4、snappy、xz、brotli 的压缩比—速度对照;多线程只在较低级别加速。

压缩原理 zstd 压缩级别 压缩速度 解压速度 内存 多线程 lz4 xz brotli Python 真实验证 动画演示
数据编码与压缩 2026-10-12

Snappy 与 LZ4:不做熵编码换来的速度

自己写解析器拆开 LZ4 block 和 Snappy 的真实输出:没有熵编码,字面量原样存放,偏移最大 65535;products 上 LZ4 的 338418 字节里元数据占 58%;速度优先的压缩器压缩比比 zstd-3 低 40% 以上;短输入的固定开销。

压缩原理 Snappy LZ4 block 格式 熵编码 偏移 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

窗口与内存:往回看得越远压缩得越小,代价是什么

窗口决定压缩器能往回看多远:重复相隔 1 MiB 要 windowLog 21 才找得到;windowLog 27 也找不到相隔 16 MiB 的重复,要开长距离匹配;压缩端声明了大窗口,解压端不准备足够内存就会失败;每个 4 KiB 对象单独压缩比整体压缩大 62%。

压缩原理 窗口 windowLog 长距离匹配 zstd 解压内存 gzip 分块 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

zstd 字典:几百字节的小记录为什么能压到原来的零头

实测 zstd 字典:单条 360 字节的商品记录无字典只有 1.25×、16 KiB 字典 3.30×;54 字节的行无字典反而变大(0.86×);1 KiB 字典就能从 288.6 降到约 130 字节/条;数据漂移后旧字典变差,重新训练恢复;解压端没有同一份字典会失败。

压缩原理 zstd 字典 小对象 字典训练 ZstdCompressionDict Python 真实验证 动画演示
数据编码与压缩 2026-10-12

gzip 与 brotli:HTTP 上的压缩,brotli 的内置字典

在 HTTP 场景里比较 gzip、brotli、zstd:brotli q5 在英文 HTML 样板上比 gzip 小 27%(应来自内置字典)、在乱码词上与 gzip 相同;requests 装了 brotli 和 zstandard 后会发 gzip, deflate, br, zstd;随机数据再压变大;brotli q11 现压缩每页 11 ms;慢网络压缩划算、快网络现压缩高级别不划算。

压缩原理 brotli gzip zstd HTTP Content-Encoding Accept-Encoding 静态字典 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

编码加压缩的组合矩阵:体积与端到端耗时

3 种编码 × 7 种压缩的矩阵:products 上最小的是 JSON + brotli q11(是未压缩 JSON 的 14.1%);zstd-3 压缩后 Protobuf 比 JSON 大 3.5%;timeseries 上 JSON + zstd-19 比 Protobuf + zstd-19 小;压缩级别越高,编码格式之间的差距越小甚至反转;解码速度 Protobuf 快 3–5 倍。

编码 压缩 组合矩阵 JSON MessagePack Protobuf snappy lz4 zstd brotli 真实验证 动画演示
数据编码与压缩 2026-10-12

压缩过的 JSON 与 Protobuf:谁更小,什么时候该换格式

压缩过的 JSON 与 Protobuf:12 列里 JSON 压缩后有 8 列更小;把价格存整数分、分类存编号、去掉可推出的字段这类数据模型优化,收益(JSON 少 12.2%,Protobuf 少 25.1%)比换格式大;最小的是改了数据模型再按列排的 JSON(703321 字节,zstd-19)。

编码 压缩 Protobuf JSON 数据模型 列式 zstd Python 真实验证 动画演示
数据编码与压缩 2026-10-12

场景一:爬虫结果落盘,JSON Lines 加 zstd 对比 sqlite BLOB

爬虫结果落盘的 8 种方式:每条单独 zstd 的 sqlite BLOB 只省 12%,加 16 KiB 字典 34%,每 100 条一块 24.6%,整个文件一个 zstd 帧 18.5%;整个帧点查 7657.5 微秒对 5.5 微秒;关系列聚合 1.1 ms 对逐行 json.loads 58.5 ms;1500 个小文件按块多占 17.8%;sqlite 删了一半数据文件不缩小。

编码 压缩 存储 sqlite JSON Lines zstd BLOB 字典 VACUUM Python 真实验证 动画演示
数据编码与压缩 2026-10-12

场景二:Redis 里的任务体与页面缓存,小对象怎么压

在独立的 redis-server 上测队列里的任务体:10 万个 376 字节的任务,JSON 每任务占 392.9 字节、Protobuf 265.8、JSON + zstd 字典 52.8;入队出队吞吐不降;50 个任务打包成一个元素每任务只占 36.1 字节;页面缓存用 zstd 字典从 68.7 MiB 降到 14.9 MiB。

编码 压缩 Redis 任务队列 小对象 zstd 字典 内存 缓存 Python 真实验证 动画演示
数据编码与压缩 2026-10-12

选型总结:一张决策表和每条结论的前提

六个场景的选型,每个都附测得的数字和前提:单条小消息(Protobuf + 字典 106.5 字节,JSON + 字典 109.1)、批量归档(xz-9 988040 最小)、批量热数据(Protobuf + lz4 读 8.2 ms)、HTTP 动态响应(zstd-3 体积乘耗时最小)、缓存(zstd + 字典省 79%)、不值得压缩的情况。

编码 压缩 选型 决策表 JSON Protobuf zstd brotli lz4 真实验证 动画演示
Scrapy 内部原理 2026-10-12

引擎主循环:一个请求从调度器到下载器再回到 spider 的路径

在 Scrapy 2.19 上给引擎的每一层挂钩子,记录一个请求的完整路径(29 个事件);默认队列是后进先出、不是严格深度优先;CONCURRENT_REQUESTS 从 1 到 24 总耗时 7.34 s 降到 0.34 s;回调返回字符串和整数也被当成 item;DontCloseSpider 之后 spider_idle 每约 5 秒重复一次。

Scrapy 引擎 调度器 下载器 信号 spider_idle 真实验证 动画演示
gRPC 2026-10-12

一个 unary 调用在网线上长什么样:HTTP/2 帧、头和 5 字节消息前缀

用自己写的 TCP 抓包代理看一次 gRPC Unary 调用的 HTTP/2 帧:请求是 HEADERS 加 DATA,响应是 HEADERS、DATA 和带 grpc-status 的 trailers;消息是 5 字节前缀加 protobuf;首次调用请求头 82 字节,第二次因为 HPACK 只有 15 字节。

gRPC HTTP/2 帧 protobuf 抓包 HPACK Go 真实验证 动画演示
京ICP备2026067502号-1京公网安备11010502063487号