Go RPC压缩需包装net.Conn实现,gzip适合大payload低延迟不敏感场景,Snappy适合高频小包;需统一压缩标识、处理粘包、避免重复压缩,实测gzip压缩率75%但延迟增2~5ms,Snappy压缩率50%且延迟无感。
在 Go 的 RPC 通信中,直接使用标准 net/rpc 包无法自动压缩数据,但可以通过包装底层连接(如 net.Conn)来实现传输层压缩。核心思路是:在客户端发送前压缩、服务端接收后解压(或反过来),且需确保两端压缩/解压逻辑严格一致。gzip 和 Snappy 是两种常用选择——gzip 压缩率高但 CPU 开销大;Snappy 压缩率低但速度快、延迟小,更适合高频低延迟 RPC 场景。
gzip 压缩适合 payload 较大(如结构体含长文本、切片、JSON 字段)且对延迟不敏感的场景。关键是用 gzip.NewReader 和 gzip.NewWriter 分别包装服务端读取器和服务端写入器(或客户端对应端),并复用连接生命周期。
gzip.NewReader(conn) 包装读取流,再传给 rpc.ServeConn;响应写入时用 gzip.NewWriter(conn) 包装写入流(注意:标准 rpc.ServeConn 不支持自定义写入器,需改用自定义 server loop)gzip.NewWriter(conn) 包装写入流发送请求,再用 gzip.NewReader(conn) 包装读取流接收响应Writer.Close() 和 Reader.Close()(或用 io.MultiReader 等技巧避免流错位),否则 gzip 流可能阻塞或校验失败Snappy 更适合微服务间高频小包通信。Go 社区常用 github.com/golang/snappy,它提供无状态的 Encode/Decode 函数,无需维护流状态,天然适配 RPC 的 request-response 模型。
snappy.Encode(nil, rawBytes) 得到压缩字节,再发送snappy.Decode(nil, compressedBytes) 解压,再反序列化为结构体标准 net/rpc 的 Client 和 Server 都基于 io.ReadWriteCloser,因此只要自定义一个支持压缩/解压的封装类型即可无缝接入。
立即学习“go语言免费学习笔记(深入)”;
CompressedConn 结构体,内嵌原始 net.Conn,重写 Read/Write 方法,在内部完成压缩/解压逻辑实测典型场景(10KB 结构体,含字符串和 slice):
p(默认级别):压缩率 ~75%,CPU 时间 +40%,延迟增加 ~2~5ms基本上就这些。压缩不是银弹,要结合数据特征、QPS、延迟容忍度做权衡。优先从 Snappy 试起,观察监控指标变化,再决定是否升级到 gzip。