字节真实面试题: GRPC序列化协议是什么?对比JSON有什么优缺点?压缩性能为什么好?

159 阅读5分钟

🕵️‍♂️后端面试题:gRPC 的序列化协议到底牛在哪?为什么比 JSON 快这么多?


有一次面试官问我:

“你知道 gRPC 为什么比 HTTP+JSON 快吗?序列化协议是什么?压缩性能又为什么好?”

我当时信心满满:“这不简单嘛,gRPC 用的是 Protobuf,体积小!”
结果面试官补刀一句:

“那你能具体说说 Protobuf 为什么小?序列化是怎么实现的?”

😅 那一刻空气突然安静,我感觉自己只答了个“标题党”。
这次,我们就来认真聊聊这道面试常客题。
但别担心,这不是死记硬背的八股,而是聊得明白、记得住、用得上的那种。


一、先来个总结:gRPC 为什么比 JSON 快?

一句话解释:
👉 「因为 gRPC 用的是 Protobuf(二进制序列化),比 JSON(文本序列化)更紧凑、更高效。」

对比项JSONProtobuf
数据格式文本二进制
数据体积❌ 大(包含字段名、引号、空格)✅ 小(使用编号和紧凑编码)
序列化速度❌ 慢(字符串拼装)✅ 快(二进制流操作)
可读性✅ 可读❌ 不可读
向前兼容性一般✅ 优秀(通过 tag 号识别)
Schema 定义动态静态(.proto 文件)

可以这么比喻:

  • JSON 是带标签的行李箱:{"name": "Tom", "age": 18}
  • Protobuf 是贴编号的托运行李:1=Tom, 2=18

看起来复杂,其实更省空间、更快上飞机 ✈️。


二、底层原理:Protobuf 到底在干什么?🤔

很多人都知道 Protobuf 是“二进制序列化”,但它到底是怎么省空间的呢?
我们先直观对比一下:

🧩 JSON 序列化结构

JSON:        {"id":123, "name":"Tom"}
              ↑   ↑      ↑    ↑     ↑
              |   |      |    |     └── 逗号
              |   |      |    └── 空格
              |   |      └── value
              |   └── 引号
              └── key

👆 可以看到,JSON 需要:

  • 写出完整的字段名("id""name"
  • 加上引号、逗号、空格等格式字符

结果:「可读性高,但冗余也高。」


⚙️ Protobuf 序列化结构

Protobuf(二进制流): [08 7B 12 03 54 6F 6D]

十六进制含义:
┌────┬────┬────┬────┬──────────────┐
│ 08 │ 7B │ 12 │ 03 │ 54 6F 6D │
└────┴────┴────┴────┴──────────────┘
  │    │    │    │         │
  │    │    │    │         └── name 内容("Tom")
  │    │    │    └── name 字段长度(3字节)
  │    │    └── name 的 tag(字段编号+类型信息)
  │    └── id 的值(123)
  └── id 的 tag(字段编号+类型信息)

示例 .proto 文件:

message User {
  int32 id = 1;     // tag = 1
  string name = 2;  // tag = 2
}

✨ 可以看出:

  • 每个字段都有个编号(tag),来自 .proto 文件定义;
  • 数值使用 「Varint 变长编码」,小数字占用更少字节;
  • 字符串用「长度 + 内容」的方式存储;

结果:**不再重复字段名、引号、格式符,自然就小得多 🚀。

✅ 对比总结:

项目JSONProtobuf
存储结构文本(key:value)二进制(tag:value)
是否包含字段名✅ 是❌ 否(用编号代替)
字段间分隔符✅ 逗号、空格❌ 无
整体大小较大非常小
机器解析速度慢(字符串处理)快(定长二进制)

三、压缩性能:Protobuf 为什么还能“压上加压”?💨

大家都知道 JSON 传输常配 gzip,对吧? 但 gzip 压 JSON 时,主要在压“重复结构”(key 名、引号、空格)。

而 Protobuf:

  • 🚫 没有冗余 key;
  • 🚫 没有空格;
  • 🚫 没有引号;
  • 🚫 已经结构化得很紧凑。

结果就是:

  • 「即使不压缩,也比 JSON+gzip 小;」
  • 「压缩之后,效果更爆炸(压缩率高、CPU 负载低)。」

这就是为什么 gRPC 在内网调用时,延迟低、吞吐高、CPU 还省。 (没错,老板看到的“成本优化”里,Protobuf 是幕后功臣 😎)


四、兼容性:Protobuf 可不是“死板”的二进制格式 💪

如果你在 .proto 文件中新增字段:

message User {
  int32 id = 1;
  string name = 2;
  string email = 3;  // 新增字段
}

老版本客户端不认识 email 字段,会直接忽略它。 不会崩、不会错。 比 JSON 的“字段名一改就炸”要友好多了。


五、那 JSON 就没地位了吗?🤝

两者各有擅长领域:

场景适合格式
外部接口(给人或第三方用)✅ JSON
内部 RPC 通信(服务间)✅ Protobuf
前端接口调试✅ JSON
高性能微服务调用✅ Protobuf

很多公司都是“「外层 HTTP + JSON,内层 gRPC + Proto」”,各取所长 👌。


六、SQL 小实验:感受下数据体积差异 📊

假设我们有张用户表:

CREATE TABLE user (
  id INT PRIMARY KEY,
  name VARCHAR(100),
  email VARCHAR(200)
);

取一条数据:

SELECT * FROM user WHERE id = 1;

JSON 序列化:

{"id":1,"name":"Tom","email":"tom@example.com"}

约 70 字节。

Protobuf 序列化(示意):

08 01 12 03 54 6F 6D 1A 0F 74 6F 6D 40 65 78 61 6D 70 6C 65 2E 63 6F 6D

仅 24 字节。

「压缩率超过 65%」,想象一下高并发场景下节省的带宽和 CPU 🤑。


七、发散一下:gRPC + JSON 也能“双剑合璧” ⚔️

gRPC 也支持 JSON,比如 「gRPC-Web」(用于浏览器端)。

  • 内部服务:gRPC + Protobuf(高性能)
  • 外部接口:gRPC-Web + JSON(兼容性)

真正兼顾性能与易用性 ✨。


八、总结 🧠

对比点JSONProtobuf
格式类型文本二进制
序列化速度
体积
压缩率一般优秀
可读性
兼容性一般优秀
适用场景外部接口内部 RPC

✅ 面试高分回答模板

“gRPC 使用 Protobuf 做二进制序列化,它用编号取代字段名,体积小; 采用变长编码和结构化二进制存储,使序列化更快、压缩性能更好。 相比 JSON,不仅网络传输更省带宽,CPU 压缩也更轻,延迟更低。”


💬 写在最后

理解 Protobuf,不只是为了背面试题, 它体现的是一种 「工程意识」: 每一个字节、每一个 bit 都被精打细算。

如果这篇文章让你豁然开朗, 记得点个「在看」支持一下 ❤️