压缩率需手动计算:压缩后字节长度 ÷ 原文字节长度;必须统一原文、压缩级别、writer复用方式及调用Close(),短文本需综合Redis解压开销、网络与CPU成本评估。

用 compress/gzip 和 compress/zstd 分别压再比长度
压缩率不是靠猜,是算出来的:压缩后字节长度 ÷ 原文字节长度。Go 里没有现成的「比压缩率」函数,得自己写小段逻辑跑一遍。重点不是选哪个库,而是确保每次测量条件一致——同一份原文、同一压缩级别、同一 writer 复用方式(或全新实例)、都调用了 Close()。
- 短文本(gzip:header + trailer 至少占 18 字节,32B 的 JSON 压完可能变成 50B,压缩率为 156%
-
zstd对小数据更友好,启用zstd.SpeedFastest时,256B 输入通常能压到 120–140B,且耗时比 gzip 低 40% - 别直接拿
bytes.Buffer.Len()当压缩后长度——必须在gz.Close()或zstdEnc.Close()后读,否则 buffer 里只是原始输入或不完整流 - 测试时用
strings.Repeat("a", n)构造高冗余文本,再用真实 JSON/XML 片段交叉验证,避免被随机字符串误导
gzip.NewWriterLevel 和 zstd.NewWriter 的级别差异
gzip 的压缩级别是整数 0–9,zstd 是预设常量(如 zstd.SpeedDefault),二者不能数值对等。比如 gzip.BestCompression(=9)和 zstd.SpeedBestCompression 虽都标“最佳”,但 zstd 在 9 级下 CPU 耗时可能翻倍而体积只少 2%,实际没必要。
- 公平对比建议:gzip 用
gzip.BestSpeed(=1) vs zstd 用zstd.SpeedFastest;gzip 用gzip.DefaultCompression(=6) vs zstd 用zstd.SpeedDefault - zstd 的
WithNoEntropy可关掉 CRC 校验,对可信链路(如进程内通信)能省 12 字节开销,gzip 没对应开关 - flate(DEFLATE 底层)可作为第三参照:它没 header,适合嵌入式协议,但 Go 里要自己补校验逻辑
为什么测出来 gzip 有时比原文还大?
这不是 bug,是格式特性。gzip 流必须包含 10 字节 header + 8 字节 trailer(CRC32 + uncompressed size),哪怕只压一个空字符串,最小合法输出也是约 20 字节。所以对 len(s) ≤ 32 的字符串,gzip 几乎必然膨胀。
- 实测:32B 随机字符串经
gzip.BestCompression压缩后为 58B;同样内容用zstd.SpeedFastest是 46B;用snappy.Encode是 42B - JSON 尤其容易踩坑:{"id":"xxx"} 这种短结构,不压缩反而更省;但 {"logs":[{...},{...},...]} 这类带重复字段名的数组,压缩率立刻跳到 40%+
- 别信「默认就该开压缩」——先采样线上真实 payload 长度分布,再决定阈值(例如只对 len > 512 的 string 压缩)
别漏掉 Redis 场景下的隐性成本
往 Redis 存字符串时,压缩决策不能只看「本地压完多小」,还得算上服务端解压开销、网络传输时间、以及客户端 CPU 是否扛得住高频压缩。LZ4 在 Redis 6.0+ 里需配全 compress-depth、compress-threads、compress-algorithm 三项才生效,光改算法没用。
立即学习“go语言免费学习笔记(深入)”;
- 加密数据(AES 输出)、Protobuf 序列化结果、base64 图片——这些本身已近熵满,LZ4 压缩率趋近 0%,纯白耗 CPU
- Redis 的
embstr编码对 - 如果读取路径是「Go client → Redis → Go client」,两端都压缩一次,不如只在客户端压、Redis 存明文,更可控
runtime.GC(),每轮用新 bytes.Buffer,别复用同一实例跨算法——zstd encoder 内部状态不清会导致后续压缩失真。


















