为什么 RPC 要比 HTTP 更快?
面试考察点
- 协议理解深度:面试官不仅仅是想知道 RPC 比 HTTP 快,更是想知道你是否理解 HTTP/1.1 的协议开销(Header 冗余、文本格式编码),以及 RPC 框架在协议层做了哪些精简。
- 序列化机制认知:考察你是否清楚 JSON/XML 这类文本序列化方式与 Protobuf、Hessian 等二进制序列化的性能差距,以及背后的原因。
- 连接管理意识:看你是否了解长连接复用、连接池管理对性能的影响,以及 HTTP 短连接模型的固有开销。
- 工程辨析能力:一个加分项——能否客观地说出 "RPC 不一定总是比 HTTP 快",比如 HTTP/2 和 gRPC 的出现已经大幅缩小了这个差距。
核心答案
先说结论:RPC 之所以比传统 HTTP(特指 HTTP/1.1 + JSON)更快,核心原因有 4 个——
| 维度 | HTTP/1.1 + JSON | RPC(Dubbo/gRPC 等) | 性能差距 |
|---|---|---|---|
| 协议格式 | 文本协议,Header 臃肿 | 自定义二进制协议,精简高效 | 报文体积差距 3~10 倍 |
| 序列化方式 | JSON(文本) | Protobuf/Hessian(二进制) | 序列化速度差距 5~20 倍 |
| 连接模型 | 短连接为主 / Keep-Alive 有限复用 | 长连接 + 连接池 | 减少 TCP 握手开销 |
| 网络模型 | BIO/NIO 混用 | NIO/Epoll 优化的 Netty | 高并发吞吐量差距明显 |
下面一个个拆开讲。
深度解析
一、协议格式:报文 "臃肿" vs "精瘦"
HTTP/1.1 的报文头是纯文本的,每次请求都要携带一大堆 Header 信息。来看个直观的例子:
上图展示了 HTTP 和 RPC 在报文结构上的核心差异。关键点:
- HTTP/1.1 的 Header 是文本格式,每次请求都要带上
Content-Type、User-Agent、Accept等一堆跟业务无关的信息。这些 Header 在内部服务调用中完全多余,但协议规定必须解析。 - Dubbo 的协议头只有固定的 16 字节(Magic Number + Flag + Status + Request ID + Data Length),极其精简。没有废话,全是干货。
- 实际场景中,一个简单的 HTTP 接口调用,Header 可能就占了 300~800 字节,而 RPC 协议头只有 16 字节。在高频调用下,这个差距会被无限放大。
二、序列化:文本 vs 二进制
这是性能差距最大的一块。
HTTP 最常用的序列化格式是 JSON,而 RPC 框架通常使用二进制序列化(Protobuf、Hessian、Kryo 等)。两者差距在哪?
上图直观展示了 JSON 和 Protobuf 在序列化后的数据差异。核心原因有三点:
- 字段名冗余:JSON 每次都要把字段名
"id"、"name"完整地传一遍,而 Protobuf 用字段编号(1、2)代替,接收端通过.proto文件反序列化时再映射回字段名。数据量直接砍半。 - 类型编码低效:JSON 中数字
12345按 ASCII 字符存储,占 5 字节。Protobuf 用 Varint(变长整数)编码,只占 3 字节。整数越大差距越明显。 - 格式符号冗余:JSON 的
{}、""、:、,这些格式符号在二进制协议中全部可以省略,用 Tag-Length-Value(TLV)结构替代。
实际压测数据参考:
| 序列化方式 | 序列化耗时 | 反序列化耗时 | 数据大小 |
|---|---|---|---|
| JSON(Jackson) | ~5ms | ~8ms | 100% |
| Hessian2 | ~3ms | ~4ms | ~60% |
| Protobuf | ~1ms | ~1.5ms | ~30% |
| Kryo | ~0.8ms | ~1ms | ~35% |
以上数据为同一条复杂对象 10 万次序列化的参考值,实际数值取决于数据结构和运行环境。
三、连接模型:短连接开销 vs 长连接复用
HTTP/1.1 默认虽然支持 Keep-Alive,但在实际使用中,很多客户端(尤其浏览器)连接复用效率并不高。而 RPC 框架天生就是基于长连接设计的。
上图对比了三种连接模型。重点说说 RPC 的优势:
- TCP 连接建立开销:一次 TCP 三次握手需要 1.5 个 RTT(Round-Trip Time),如果走 TLS 还要额外 2 个 RTT。在同机房 RTT 约 0.5ms,跨机房可能 5~30ms。高频短连接场景下,这个开销非常可观。
- RPC 框架直接基于 Netty 做 NIO 多路复用,一个 TCP 连接上可以同时跑多个请求,通过 Request ID 做关联,互不阻塞。
- Dubbo 还支持连接池和多连接,可以根据并发量动态调整。默认情况下,消费者与每个提供者建立单个长连接,对于高并发场景可以配置多个连接。
四、网络模型:BIO vs NIO
这个维度很多人会忽略。
传统的 HTTP 服务(比如早期的 Servlet 容器)多采用 "一请求一线程" 的 BIO 模型,并发量大的时候线程数暴涨,上下文切换开销巨大。
而主流 RPC 框架(Dubbo、gRPC)底层都是基于 Netty 的 NIO 模型:
- 少量线程(通常等于 CPU 核心数)即可处理大量并发连接
- 基于 Linux
epoll的 IO 多路复用,单线程可以同时监听数千个连接 - 避免了线程上下文切换和锁竞争的开销
说白了,网络模型决定了 "天花板" 有多高。协议再精简,如果每个请求都占用一个线程,并发一上去照样扛不住。
五、一个容易被忽略的点——RPC 框架的 "额外优化"
除了上面 4 个核心差异,成熟的 RPC 框架还做了一些 HTTP 原生不提供的优化:
- 服务发现:RPC 框架内置注册中心(Nacos、ZooKeeper),自动感知服务上下线,HTTP 需要额外引入负载均衡组件
- 智能路由:基于权重、一致性哈希、同机房优先等策略的流量调度
- 熔断降级:集成 Sentinel、Hystrix 等组件,快速失败
- 泛化调用:不需要客户端 SDK,直接传参调接口
这些不算 "速度" 上的优势,但它们让 RPC 在微服务架构中的整体效率远高于裸 HTTP 调用。
常见误区
误区:HTTP 一定比 RPC 慢。
这个说法已经过时了。HTTP/2 引入了二进制分帧、多路复用、Header 压缩(HPACK),性能大幅提升。gRPC 更是直接基于 HTTP/2 + Protobuf,性能已经非常接近传统 RPC 框架。
所以更准确的说法是:RPC(自定义协议)比 HTTP/1.1 + JSON 快,但 HTTP/2 + Protobuf 的性能已经和传统 RPC 不相上下了。
面试高频追问
-
追问一:既然 RPC 这么好,为什么还要用 HTTP?
HTTP 的优势在于 通用性和生态。浏览器原生支持 HTTP,API 网关、CDN、防火墙都围绕 HTTP 协议工作。对外暴露的 API(OpenAPI、移动端接口)几乎都用 HTTP,对内微服务间调用才用 RPC。这也是为什么很多公司采用 "外 HTTP 内 RPC" 的架构。
-
追问二:gRPC 算 RPC 还是 HTTP?
gRPC 是基于 HTTP/2 的 RPC 框架。它用 HTTP/2 做传输层,用 Protobuf 做序列化,兼具了 HTTP 的通用性和 RPC 的高性能。所以说,HTTP 和 RPC 并不是对立的,gRPC 就是两者结合的产物。
-
追问三:Dubbo 和 Spring Cloud(OpenFeign)的性能差距大吗?
Dubbo 使用自定义 TCP 协议 + Hessian2/Protobuf 序列化,OpenFeign 本质是 HTTP + JSON。在同样的硬件条件下,Dubbo 的吞吐量通常是 OpenFeign 的 2~5 倍,延迟也低 30%~50%。不过 Spring Cloud 6 已经开始支持 gRPC,差距在缩小。
常见面试变体
- 变体一:"HTTP 和 RPC 的本质区别是什么?"
- 变体二:"为什么微服务内部调用推荐用 RPC 而不是 HTTP?"
- 变体三:"gRPC 和 Dubbo 性能上有什么差异?"
- 变体四:"什么场景只能用 HTTP,不能用 RPC?"
记忆口诀
RPC 快的四个字:"精、二、长、N"
- 精:协议精简,16 字节头部 vs 几百字节 HTTP Header
- 二:二进制序列化,体积小、速度快
- 长:长连接复用,省去 TCP 握手开销
- N:NIO 网络模型,少量线程扛高并发
总结
一句话:RPC 比传统 HTTP/1.1 快,核心在于 协议更精简、序列化更高效、连接复用更好、网络模型更优秀。但别忘了,HTTP/2 + gRPC 已经在缩小这个差距,面试时千万别说 "HTTP 就是比 RPC 慢",要说清是 "HTTP/1.1 + JSON" vs "自定义协议 + 二进制序列化" 的差异,这才是面试官想听的。
