压缩比精确计算为原始字节长度除以gzip.close()后缓冲区长度;gob需注意类型描述开销,单条记录时可能不如json+gzip,批量写入则优势显著;小数据(

直接对比原始字节长度与压缩后长度
压缩比不是靠猜或估算,而是用 len() 算两个数字再相除:原始序列化字节长度 ÷ 压缩后字节长度。注意分子是未压缩的完整字节流(比如 json.Marshal() 返回的 []byte),分母是调用 gzip.Writer.Close() 后写入目标(如 bytes.Buffer)的最终长度。
常见错误是只看 Write() 的返回值,它不包含 gzip 尾部(CRC、ISIZE 等),会导致分母偏小、压缩比虚高。必须等 Close() 完成才读取缓冲区长度。
-
json.Marshal()或gob.NewEncoder().Encode()输出原始字节 → 记下len(b) - 用
gzip.NewWriter(buf)写入该字节流 → 调用gz.Close() - 此时
buf.Len()才是真实压缩后大小 - 压缩比 =
float64(len(b)) / float64(buf.Len())
区分 gob 的“首次写入开销”和批量写入效率
gob 的压缩比分析容易误判,因为它在流开头写入类型描述信息(type table)。单个结构体序列化时这部分占比极高;但连续写入同类型多个值时,后续每条仅需极小开销(如 12 字节/条)。所以测压缩比前必须明确场景:
- 只存一条记录?那
gob+gzip可能不如纯json+gzip—— 类型元数据无法摊薄 - 批量写入百万条?复用同一个
gob.Encoder,再套gzip,压缩比会远超 JSON,甚至逼近手工二进制编码 - 别用
gob.NewEncoder(bytes.Buffer)每次新建 —— 每次都重写 type table,失去流式优势
避免对小数据盲目压缩
小于 100 字节的结构体,gzip 压缩后可能反而更大(因 gzip header 固定占 10+ 字节)。实测中,json.Marshal(&struct{A,B int}) 生成约 20 字节,压缩后常为 35–40 字节 —— 压缩比 0.5,即膨胀了。
建议加阈值判断:
- 先
json.Marshal()得到b - 若
len(b) ,直接用原字节,跳过 <code>gzip - 否则走压缩流程,并记录实际压缩比用于后续策略调整
这个阈值不是绝对的,取决于结构体字段是否含长字符串 —— 纯数字/短字段的小结构体,基本不值得压。
用 flate 替代 gzip 测更细粒度压缩收益
compress/flate 是 gzip 和 zlib 的底层算法,去掉 header 和尾部校验后,能更干净地反映纯内容压缩能力。适合做基准对比:
-
flate.NewWriter(buf, flate.BestSpeed)→ 快速压,看最低压缩比 -
flate.NewWriter(buf, flate.BestCompression)→ 慢速压,看理论极限 - 对比两者输出长度,判断业务是否真需要高压缩率
- 注意:
flate.Writer同样要Close()才算数,且不能直接被gzip.NewReader()解开 —— 它不是标准 gzip 格式
真正上线仍推荐用 gzip,兼容性优先;但分析压缩潜力时,flate 能帮你排除格式封装干扰,看清数据本身可压空间。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











