Netty 有哪些序列化协议?
结论先行:Netty 自己只提供序列化的“接口与几个现成编解码器”(Java 原生、Protobuf、Thrift、JBoss Marshalling、Kryo、MessagePack 等由扩展包提供),协议本身不绑定。选型看跨语言、体积、兼容演进三条线,工程上最常用 Protobuf,其次 JSON。
一、可选协议对照
| 协议 | 编解码器 | 跨语言 | 体积 | 兼容演进 | 备注 |
|---|---|---|---|---|---|
| Java 原生 | ObjectEncoder/ObjectDecoder | 否 | 大 | serialVersionUID 严格 | 有反序列化漏洞面,不推荐 |
| Protobuf | ProtobufEncoder/Decoder | 是 | 很小 | 字段号演进,最佳 | 需 IDL 与代码生成 |
| Thrift | ThriftMessage 扩展 | 是 | 小 | 中等 | 已有 Thrift 生态时用 |
| JBoss Marshalling | MarshallingEncoder/Decoder | 否 | 中 | 中等 | 比 Java 原生快,需额外依赖 |
| Kryo | 社区扩展 | 否 | 很小 | 需注册类,版本敏感 | 内部高性能场景 |
| MessagePack | 社区扩展 | 是 | 小 | 中等 | 类 JSON 的二进制 |
| JSON | 自定义 MessageToByteEncoder | 是 | 大 | 宽松 | 可读、易调试 |
二、Java 原生序列化为什么不推荐
| 问题 | 说明 |
|---|---|
| 体积 | 带完整类描述与字段名,通常比 Protobuf 大 3~5 倍 |
| 性能 | 反射 + 元数据解析,CPU 开销高 |
| 安全 | 反序列化可构造任意对象链,历史漏洞多 |
| 兼容 | 改类结构、换包名极易失败 |
三、Protobuf 的装配
syntax = "proto3";
option java_package = "com.demo.proto";
message Order {
int64 id = 1;
string userId = 2;
int32 amount = 3;
}
Protobuf 是变长编码,没有固定消息长度,所以必须先用长度字段切帧,再交给 ProtobufDecoder:
ch.pipeline()
.addLast(new ProtobufVarint32FrameDecoder()) // 按 varint 长度切帧
.addLast(new ProtobufDecoder(Order.getDefaultInstance()))
.addLast(new ProtobufVarint32LengthFieldPrepender())
.addLast(new ProtobufEncoder())
.addLast(new OrderHandler());
四、自定义 JSON 编解码
public class JsonEncoder extends MessageToByteEncoder<Object> {
@Override
protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) {
byte[] body = JsonCodec.write(msg);
out.writeInt(body.length); // 与 LengthFieldBasedFrameDecoder 配套
out.writeBytes(body);
}
}
配套解码:
ch.pipeline()
.addLast(new LengthFieldBasedFrameDecoder(1 << 20, 0, 4, 0, 4))
.addLast(new JsonDecoder(Order.class)) // 内部把 ByteBuf 读成对象
五、选型判断
| 条件 | 选择 |
|---|---|
| 需要跨语言、长期演进 | Protobuf |
| 内部 Java 服务、追求吞吐 | Kryo 或 Protobuf |
| 需要人眼可读、调试方便 | JSON |
| 已有 Thrift 体系 | Thrift |
| 与老系统兼容 | JBoss Marshalling(而非 Java 原生) |
常见追问
- 追问:Protobuf 为什么必须先切帧?消息体是变长 varint 编码,解析器不知道边界就无法判断下一条消息从哪开始。
- 追问:Kryo 有什么坑?类注册顺序与版本强相关,生产环境升级容易反序列化失败,需要严格的版本管理。
- 追问:JSON 会不会太慢?在高 QPS 小报文场景确实明显,但可读性与排障效率的价值也很高,多数业务系统可以接受。
小结
- Netty 不绑定序列化,协议可插拔,编解码器放 pipeline 即可。
- Protobuf 是跨语言与演进的最佳选择,必须配长度字段切帧。
- Java 原生序列化体积大、有安全风险,不要在新系统使用。
- JSON 胜在可读,Kryo 胜在性能,按场景取舍。