RPC 中常见的序列化协议有哪些?如何选择?
简化版
序列化是把对象转成字节流(用于网络传输)、反序列化是还原回对象。RPC 里选序列化协议要看性能、体积、跨语言、易用性几个维度。常见的:Protobuf(Google,二进制、体积最小、性能高、跨语言,但要写 IDL)、Hessian(二进制、跨语言、无需 IDL,Dubbo 默认)、Kryo/FST(Java 专用,性能极高但不跨语言)、JSON(文本、可读性好、通用跨语言,但体积大性能低)、Java 原生序列化(简单但体积大、性能差、有安全漏洞,不推荐)。追求性能和跨语言选 Protobuf,Java 内部图省事用 Hessian/Kryo,对外或调试友好用 JSON。
详细版
常见序列化协议对比:
| 协议 | 类型 | 性能 | 体积 | 跨语言 | 易用性 |
|---|---|---|---|---|---|
| Protobuf | 二进制 | 高 | 最小 | 是 | 需写 .proto IDL |
| Hessian | 二进制 | 较高 | 小 | 是 | 无需 IDL(Dubbo 默认) |
| Kryo | 二进制 | 极高 | 小 | 否(Java) | 简单 |
| FST | 二进制 | 极高 | 小 | 否(Java) | 简单 |
| JSON | 文本 | 低 | 大 | 是 | 可读、通用 |
| Java 原生 | 二进制 | 低 | 大 | 否 | 简单但有安全漏洞 |
选择维度:性能、序列化后体积、是否跨语言、是否需要 IDL、可读性/调试、兼容性(字段增删的向前向后兼容)。
完整版教学
一、序列化在 RPC 中的作用与重要性
RPC 调用要跨网络传输方法参数和返回值,但网络只能传字节流,不能直接传 Java 对象。所以要序列化(对象 → 字节流)发送、反序列化(字节流 → 对象)接收。
序列化协议的选择直接影响 RPC 的性能——它决定了:
- 序列化/反序列化的速度(CPU 开销)。
- 序列化后的数据体积(影响网络传输量、带宽)。
在高频调用的 RPC 场景,序列化是核心性能点之一。所以要根据场景选合适的协议,权衡性能、体积、跨语言、易用性。
二、Protobuf:高性能跨语言首选
Protobuf(Protocol Buffers,Google 出品) 是目前最流行的高性能序列化协议,也是 gRPC 的默认序列化。
- 优点:二进制格式、体积最小(有高效的编码如 varint)、序列化/反序列化性能高、跨语言(支持几乎所有主流语言)、向前向后兼容好(字段用编号标识,增删字段兼容性强)。
- 代价:需要编写
.proto的 IDL(接口描述文件),再用工具生成各语言的代码——多一步,但换来强类型和跨语言。 - 适用:追求极致性能 + 跨语言的场景,gRPC 标配。
三、Hessian:Dubbo 默认,无需 IDL
Hessian 是一种二进制序列化协议,Dubbo 默认使用 Hessian2。
- 优点:二进制、体积较小、性能较好、跨语言,且不需要写 IDL——直接序列化对象即可,比 Protobuf 使用更简便。
- 适用:Java 为主、想要不错的性能又不想写 IDL 的场景。Dubbo 选它作默认,就是权衡了「性能」和「易用(无需 IDL)」。
四、Kryo / FST:Java 专用,性能极致
Kryo 和 FST 是Java 专用的高性能序列化库。
- 优点:性能极高、体积小——因为专为 Java 优化,不用考虑跨语言的通用性,可以做得很极致。
- 缺点:不跨语言(只能 Java ↔ Java),且有些配置(如注册类)稍复杂。
- 适用:纯 Java 内部服务、追求极致性能、不需要跨语言的场景。Dubbo 也支持配置用 Kryo/FST 替换默认的 Hessian 以提升性能。
五、JSON 与 Java 原生序列化
JSON:
- 优点:文本格式、可读性极好、通用、跨语言——任何语言都能解析,调试方便(能直接看懂)。
- 缺点:体积大(文本冗余,字段名重复出现)、性能低(文本解析慢)。
- 适用:对性能不敏感、追求可读性和通用性的场景,尤其对外 HTTP API。RPC 内部高频调用一般不用 JSON。
Java 原生序列化(Serializable):
- 优点:Java 内置、用起来最简单(实现
Serializable即可)。 - 缺点:体积大、性能差、不跨语言,而且历史上有严重的反序列化安全漏洞(反序列化恶意数据可导致远程代码执行)。强烈不推荐用于 RPC。
六、常见误区与追问
这道题面试时最容易丢分的地方,是把「RPC 序列化协议对比」答成一段泛泛的组件介绍。更稳的答法是先给结论,再沿着 远程调用链路 拆清楚流程,最后补上异常场景、数字边界和选型取舍。
| 回答层次 | 要讲清的内容 | 容易漏掉的边界 |
|---|---|---|
| 核心定义 | 序列化选择要看性能、包大小、可读性、跨语言、Schema 演进和安全性 | 不要停在名词解释 |
| 流程机制 | 对象转字节 -> 网络传输 -> 服务端按协议解码 -> 执行方法 -> 响应再编码返回 | 说明谁触发、谁存储、谁通知、谁兜底 |
| 工程取舍 | JSON 可读但字段名冗余,Protobuf 二进制紧凑且跨语言好,Hessian 在 Java RPC 生态常见 | RPC 让调用写法像本地方法,但失败语义、网络延迟和版本兼容必须按远程系统处理 |
RPC 序列化协议对比 面试拆解:
1. 对象转字节
2. 网络传输
3. 服务端按协议解码
4. 执行方法
5. 响应再编码返回
记忆钩子:先拆代理、序列化、传输、寻址、容错,再说明超时、重试、幂等这些工程边界;回答时一定要落到题目中的「RPC 序列化协议对比」,不要把相邻中间件的能力混着讲。
- 误区:序列化只影响传输速度。 它还影响接口演进、跨语言、调试、兼容性和安全风险。
- 误区:JSON 最适合所有 RPC。 JSON 易读易调试,但包体大、类型约束弱,高性能内部调用常选二进制协议。
- 误区:Protobuf 字段名可以随便改。 Protobuf 兼容演进依赖字段编号,随意复用编号会破坏兼容。
- 追问:Hessian 有什么特点? 它是二进制序列化,Java 生态使用较多,Dubbo 早期默认常见。
- 追问:为什么 Protobuf 跨语言能力强? 它基于 IDL 生成多语言代码,字段类型和编号契约明确。
- 追问:序列化安全要注意什么? 避免反序列化不可信数据触发任意类加载或 gadget 链攻击。
七、加强记忆
序列化 = 对象 ↔ 字节流,是 RPC 的核心性能点(影响速度和体积)。选型看性能、体积、跨语言、易用性、兼容性:Protobuf——二进制、体积最小性能高、跨语言、兼容性好,但需写 .proto IDL,gRPC 标配、高性能跨语言首选;Hessian——二进制、跨语言、无需 IDL,Dubbo 默认,易用与性能平衡;Kryo/FST——Java 专用、性能极致但不跨语言,纯 Java 内部提性能用;JSON——文本、可读通用跨语言但体积大性能低,适合对外 HTTP API/调试;Java 原生序列化——简单但体积大、慢、不跨语言、有安全漏洞,不推荐。口诀:要跨语言高性能选 Protobuf、Java 内部图省事用 Hessian/Kryo、对外调试友好用 JSON、别用 Java 原生。