适用读者:被问"为什么不用 REST 全替代 RPC"的人;要在 gRPC / HTTP+JSON 之间选型的人。
前置:S02-B06(HTTP 与 HTTPS)、S02-B08(长连接)。
实测环境:Python 3.12 + protobuf 7.36.2(venv);实测日期 2026-11-05。
覆盖旧文:A-913(HTTP 与 RPC 的区别,81 点)、A-1050(为什么 RPC 比 HTTP 快,94 点)、A-1564(Feign 与 HTTP 客户端,56 点,跨 S17)= 231 点。
覆盖扩展:E-S02-017(Protobuf vs JSON)、E-S02-018(HPACK)。
上一篇:S02-B08 · 实时通信的稳定性:断线、重连、心跳与幂等
下一篇:S02-B10 · 从 OpenAPI 到可执行工具。
1. 一句话结论
RPC 与 HTTP 不是同一层的东西。 HTTP 是"传输协议",RPC 是"远程调用的编程模型"——RPC 完全可以跑在 HTTP 之上(gRPC 就是)。
所以"RPC 比 HTTP 快"这句话严格来说不成立,正确的说法是:
"二进制序列化 + 头部压缩 + 长连接复用 + 更少的语义开销" 这四件事加起来,让典型 RPC 调用比典型 REST/JSON 调用更快。
2. 实测:序列化能省多少
同一份业务记录(id、用户名、金额、状态、标签数组):
# 单条
Protobuf = 43 B | JSON(UTF-8) = 106 B | 比例 2.47x
# 1000 条
Protobuf = 43000 B | JSON = 108000 B | 比例 2.51x
# 解析耗时(10000 次)
Protobuf 0.016s | JSON 0.090s
| 指标 | Protobuf | JSON | 差异 |
|---|---|---|---|
| 单条体积 | 43 B | 106 B | 2.47× |
| 批量体积 | 43 KB | 108 KB | 2.51× |
| 解析 1 万次 | 0.016 s | 0.090 s | 5.6× |
为什么差这么多:
| 原因 | 说明 |
|---|---|
| 字段名不传输 | JSON 每条都带 "user_name":;Protobuf 只传字段号(1、2、3) |
| 变长整数编码 | 1234567890123 在 JSON 是 13 个字符,Protobuf 用 varint 只需 6 字节 |
| 无引号/无逗号/无括号 | 结构信息在 schema 里,不在报文里 |
| 解析是二进制偏移 | 不需要词法分析,直接按 schema 读 |
别过度引申:2.5 倍的体积差异在大带宽场景意义有限;真正的收益在"高频小消息 + 移动网络"。
3. 性能差距的四个来源
| 来源 | HTTP/1.1 + JSON | RPC(gRPC 为例) | 差多少(量级) |
|---|---|---|---|
| ① 序列化 | 文本,体积大、解析慢 | 二进制,紧凑、解析快 | 2–5×(本文实测) |
| ② 头部开销 | 每个请求几百字节文本头 | HTTP/2 + HPACK 压缩 | 高频小请求下显著 |
| ③ 连接复用 | keep-alive 也可复用 | 多路复用(一条连接并发多流) | 并发高时显著 |
| ④ 语义开销 | 每次要构造/解析 HTTP 语义 | 直接方法调用 → 编解码 | 小但存在 |
3.1 关于 ②:HPACK 到底省了什么(E-S02-018)
HTTP/2 的头部压缩用"静态表 + 动态表":content-type、user-agent 这类重复出现的头部只传一个索引号,不再传字符串。
实测含义:如果每个请求头部 400 字节、body 50 字节,那么 HTTP/1.1 下 89% 的流量是头部;HTTP/2 压缩后可能降到几十字节——这就是"高频小请求"场景下 HTTP/2 的收益来源。
4. 对照表:REST/JSON 与 gRPC
| 维度 | REST + JSON | gRPC |
|---|---|---|
| 契约 | OpenAPI(可选) | .proto 强制 |
| 序列化 | JSON | Protobuf |
| 传输 | HTTP/1.1 或 2 | 必须 HTTP/2 |
| 浏览器直连 | ✅ 原生 | ❌ 需要 grpc-web + 代理 |
| 流式 | SSE/WebSocket 另配 | 内建四种流(单向/服务端/客户端/双向) |
| 可调试性 | ✅(curl 直接看) |
⚠️ 需 grpcurl 与 proto |
| 版本兼容 | 靠约定 | 字段号 + reserved(更严格) |
| 生态 | 全语言、全工具 | 主流语言,工具链较重 |
5. 选型判据(三问)
谁在调用?
├── 浏览器 / 第三方 / 公开 API → HTTP + JSON(REST)
└── 内部服务之间
├── 高频、低延迟、强契约 → gRPC
└── 低频、调试优先 → HTTP + JSON 也行
| 判据 | 选 HTTP/JSON | 选 gRPC/RPC |
|---|---|---|
| 调用方是浏览器 | ✅ | ❌ |
| 需要人工调试/抓包看内容 | ✅ | ⚠️ |
| 内部服务、QPS 高、消息小 | ⚠️ | ✅ |
| 需要双向流(实时同步) | ❌ | ✅ |
| 跨语言、多团队 | ⚠️ | ✅(proto 是契约) |
一句总结:对外用 HTTP,对内视规模用 RPC,两者可以共存(网关做转换)。
6. 关于 Feign 与 HTTP 客户端(A-1564,跨 S17)
旧文 A-1564 是"Feign 与 HTTP 客户端"的面试口径。这里只给结论,细节归 S17:
| 客户端 | 特点 | 适用 |
|---|---|---|
RestTemplate |
同步阻塞、简单 | 传统 Spring 项目 |
WebClient |
响应式、非阻塞 | 高并发、Spring WebFlux |
| OpenFeign | 声明式接口,集成服务发现与负载均衡 | Spring Cloud 微服务 |
HttpClient(JDK 11+) |
支持 HTTP/2、异步 | 轻量场景 |
判据:已经在 Spring Cloud 体系内 → Feign;否则不要为了"声明式"引入整套 Cloud 依赖。
7. 五个误区
| 误区 | 真相 |
|---|---|
| "RPC 比 HTTP 快,所以都该用 RPC" | RPC 常跑在 HTTP/2 上;差距主要来自序列化与头部 |
| "JSON 慢到不能用" | 差异 2–5 倍,但网络 RTT 往往是主要成本 |
| "gRPC 一定省带宽" | 小消息省;大二进制(图片/文件)两者都不该走 RPC |
| "HTTP/2 开了就快" | 高频小请求才明显;大文件传输提升有限 |
| "Feign 就是 HTTP 客户端" | 它是"声明式 + 服务发现 + 负载均衡"的组合,重的是生态 |
8. 自测
- 为什么说"RPC 比 HTTP 快"这句话不严谨?
- 序列化差异的四个具体来源是什么?
- HPACK 在什么场景下收益最大?
- 浏览器直连的 REST 与 gRPC,本质限制在哪?
- 内部服务 QPS 很高但消息很大(几十 KB),你会怎么选?
9. 下一篇
S02-B10 · 从 OpenAPI 到可执行工具:API 描述如何变成插件
接口协议选完,下一个问题是"怎么让机器理解一个 API"。下一篇把旧文 A-647/A-649 的内容重组成:OpenAPI 描述 → 工具 schema → 真实 HTTP 调用 的完整链路,并指出"缺哪几项就无法安全调用"。
本篇属于系列《S02 · 计算机与网络基础》。旧文来源:A-913、A-1050、A-1564(跨 S17);扩展点 E-S02-017/018。Protobuf/JSON 对比为 2026-11-05 实测(protobuf 7.36.2)。