默认 gob 编码在 RPC 中不够快,因其编码体积大、解析慢、不跨语言,高并发或大数据量下 CPU 和带宽消耗高;优化应换用 protobuf+gRPC 或在 net/rpc 上加压缩层。
gob 编码在 RPC 中不够快Go 标准库的 net/rpc 默认用 gob 序列化,它虽支持任意 Go 类型,但编码体积大、解析慢,且不跨语言。高并发或大数据量场景下,gob 的 CPU 占用和网络带宽消耗会明显成为瓶颈。尤其当结构体字段多、嵌套深或含大量字符串时,gob 生成的字节流比 JSON 还大,更远不如 Protocol Buffers。
protobuf + grpc-go 替代原生 net/rpc
最有效的优化不是“调优 gob”,而是换掉整个协议栈。gRPC 基于 HTTP/2 和 Protocol Buffers,天然支持二进制紧凑编码、流式传输、头部压缩和连接复用。
.proto 文件,用 protoc 生成 Go 代码(含 Unmarshal/Marshal 实现)grpc.NewServer() 启动,注册的是实现了 xxxServer 接口的结构体grpc.Dial() 连接,调用生成的 Client 方法,底层自动完成序列化/反序列化proto.Marshal 或 proto.Unmarshal —— gRPC 已封装在 call lifecycle 中service UserService {
rpc GetUser(GetUserRequest) returns (GetUserResponse);
}
message GetUserRequest {
int64 id = 1;
}
message GetUserResponse {
string name = 1;
int32 age = 2;
}
net/rpc 的前提下启用压缩如果无法迁移到 gRPC(如需兼容旧客户端),可在 net/rpc 上层加一层压缩。关键点是:压缩必须在编码后、发送前做,解压必须在接收后、解码前做。不能压缩原始 struct,而要压缩 gob 或 json 输出的字节流。
github.com/klauspost/compress/gzhttp 包包装 http.ResponseWriter 和 http.Request,但仅适用于基于 HTTP 的 RPC(如 net/rpc/jsonrpc)io.ReadWriteCloser,内部套 gzip.NewReader / gzip.NewWriter
gzip 的 gzip.BestSpeed 模式(默认),改用 gzip.BestCompression 只在服务端出口处设一次,客户端不参与压缩决策jsonrpc 比 gob 更慢?那为什么还用它纯性能看,jsonrpc 确实比 gob 慢——JSON 解析开销大、无类型信息、字符串重复多。但它唯一不可替代的价值是**调试友好性与跨语言互通**。生产环境不应直接暴露 jsonrpc 给前端,但可作为内部运维接口(如 Prometheus 指标导出、健康检查端点)。
net/rpc/jsonrpc.NewClient 连接时,确保服务端启动的是 jsonrpc.ServeConn 而非 gob.ServeConn
jsonrpc 中传 time.Time 或 map[interface
{}]interface{} —— JSON 不支持,会 panicencoding/json 的 Marshaler 接口实现,或改用 github.com/json-iterator/go 加速 2–3 倍真正容易被忽略的是:序列化优化永远要配合传输层调优。比如 gRPC 的 MaxConcurrentStreams、HTTP/2 的 WriteBufferSize、TCP 的 SO_SNDBUF,这些参数不对齐,再快的序列化也白搭。