Netty 有哪些序列化协议?

#中间件#面试八股

Netty 有哪些序列化协议?

结论先行:Netty 自己只提供序列化的“接口与几个现成编解码器”(Java 原生、Protobuf、Thrift、JBoss Marshalling、Kryo、MessagePack 等由扩展包提供),协议本身不绑定。选型看跨语言、体积、兼容演进三条线,工程上最常用 Protobuf,其次 JSON。

一、可选协议对照

协议编解码器跨语言体积兼容演进备注
Java 原生ObjectEncoder/ObjectDecoder否大serialVersionUID 严格有反序列化漏洞面,不推荐
ProtobufProtobufEncoder/Decoder是很小字段号演进,最佳需 IDL 与代码生成
ThriftThriftMessage 扩展是小中等已有 Thrift 生态时用
JBoss MarshallingMarshallingEncoder/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 胜在性能,按场景取舍。
笔记加载中…