Dubbo 支持哪些序列化方式?
结论先行:Dubbo 默认用 Hessian2,另支持 Fastjson2、Protobuf、Kryo、FST、Java 原生、Avro、MessagePack、Thrift 等,Dubbo 3 的 Triple 协议默认用 Protobuf。选型看三点:跨语言需求、性能与体积、以及“字段增删是否兼容”的演进要求。
一、常见实现对比
| 方式 | 跨语言 | 体积 | 性能 | 兼容性 | 适用场景 |
|---|---|---|---|---|---|
| Hessian2(默认) | 较好 | 中 | 中 | 字段增删兼容,忽略未知字段 | Java 为主的内部服务 |
| Protobuf | 强 | 小 | 高 | 按字段号演进,兼容性最好 | 跨语言、Triple/gRPC |
| Fastjson2 | 弱 | 中大 | 高 | 依赖字段名,较宽松 | 调试友好、JSON 生态 |
| Kryo | 弱 | 小 | 很高 | 需注册类,版本敏感 | 内部高频调用 |
| FST | 弱 | 小 | 高 | 需 JDK 兼容类 | 替代 Java 原生 |
| Java 原生 | 弱 | 大 | 低 | serialVersionUID 严格 | 几乎不推荐 |
| Avro | 强 | 小 | 高 | Schema 演进强 | 大数据管道 |
二、为什么默认是 Hessian2
Hessian2 是自描述二进制协议:每个字段带类型与名字,因此消费端可以在不知道对方类结构细节的情况下解析,字段增删通常不报错。它不需要预先编译 IDL,对 Java 生态最省事,代价是体积比 Protobuf 大、解析比手写编解码慢。
Hessian2 编码示意(对象 → 字节流)
[H][0x02] 版本
'C' 类定义:类名长度 + 类名 + 字段数 + 字段名列表
'O' 对象实例:按字段顺序写值(int/string/date 各有类型标记)
三、切换与配置
全局指定:
dubbo:
protocol:
name: dubbo
serialization: hessian2 # 可选 fastjson2 / protobuf / kryo / java
方法级覆盖:
@DubboReference(serialization = "fastjson2", timeout = 800)
private OrderService orderService;
Protobuf 需要 IDL 与生成类:
syntax = "proto3";
option java_package = "com.demo.api";
message UserReq {
int64 id = 1;
string name = 2;
}
service UserService {
rpc GetById (UserReq) returns (UserResp);
}
四、切换序列化时的兼容性红线
| 操作 | Hessian2 | Protobuf | Java 原生 |
|---|---|---|---|
| 新增字段 | 兼容 | 兼容(新字段号) | 兼容(需同 serialVersionUID) |
| 删除字段 | 通常兼容 | 保留字段号即可 | 不兼容 |
| 改字段类型 | 可能失败 | 不兼容 | 不兼容 |
| 改类名/包名 | 失败 | 由 IDL 决定 | 失败 |
上线时必须“先升提供者、后升消费者”,或双跑两种序列化做灰度;不能一边 hessian2 一边 protobuf 混调同一接口。
常见追问
- 追问:Hessian2 有哪些坑?它对某些集合类型、循环引用、大对象处理不好;序列化漏洞也出现过,所以要升级到修复版本并限制反序列化类。
- 追问:为什么不用 Java 原生序列化?体积大、性能差、强依赖类结构、有反序列化漏洞面。
- 追问:Triple 协议为什么用 Protobuf?它是 gRPC 兼容协议,靠 HTTP/2 + Protobuf 实现跨语言与流式调用。
小结
- 默认 Hessian2,省事但体积与性能一般。
- 跨语言选 Protobuf,内部极致性能选 Kryo/FST,调试友好选 JSON。
- 换序列化前先确认字段演进策略与灰度顺序。
- 序列化不是免费开关,它决定了接口的兼容边界。