有了 HTTP,为什么还要 RPC?聊聊这两个东西到底差在哪
一个很自然的疑问
学网络编程的时候,大部分人都是先接触 HTTP。浏览器敲个地址,发个请求,拿个响应,这套东西太熟悉了。
然后突然有一天,面试官问你:"你们微服务之间用什么通信?"
你说 HTTP。
他接着问:"那为什么不用 RPC?HTTP 和 RPC 有什么区别?"
你愣住了。
这个问题其实很多工作两三年的程序员都说不清楚。不是他们菜,而是 HTTP 太常用了,日常开发里很少有机会去想"除了 HTTP 还能用什么"。
今天把这俩的关系掰扯清楚。
先别对立起来,它俩不是一个层面的东西
很多人一上来就把 HTTP 和 RPC 当对手,好像用了这个就不能用那个。这种理解从一开始就偏了。
HTTP 是应用层协议。 它的核心工作是定义数据怎么打包、怎么传输、怎么解析。请求行、状态码、Header、Body,一套固定的格式,浏览器认识,服务器也认识。
RPC 是一种思想,或者说设计理念。 它的目标是让你调用远程服务的时候,感觉就像在调本地方法一样。你只关心入参和返回值,网络通信的细节全部被屏蔽掉。
打个比方:
- HTTP 像是快递公司的标准化包装规范------箱子尺寸、面单格式、签收流程,全给你定死了。
- RPC 像是**"让对方帮你办一件事"这种协作方式**------你不在乎他是坐地铁来的还是打车来的,你只在乎他把事办成没有。
所以严格来说,HTTP 和 RPC 不是二选一的关系。RPC 是一种"调用思想",HTTP 是一种"传输手段"。很多 RPC 框架底层就是用 HTTP 传输的,比如 gRPC 跑在 HTTP/2 上,Spring Cloud 的 OpenFeign 也是基于 HTTP。
那问题来了:既然底层都可以是 HTTP,为什么不直接手写 HTTP 调用,还要套一层 RPC 框架?
核心区别:你到底想要什么能力
1. 设计定位不同
HTTP 设计之初是为了浏览器和服务器之间的文档传输。它天然是面向"资源"的,URL 定位资源,GET/POST/PUT/DELETE 操作资源------这就是 RESTful 那套思想。
RPC 设计之初是为了程序与程序之间的方法调用 。它天然是面向"动作"的,getUserById(123)、createOrder(orderInfo),跟你在本地写代码的思路一模一样。
HTTP:"我要获取用户资源" → GET /users/123
RPC:"帮我查一下 ID 为 123 的用户" → userService.getUserById(123)
看出区别了吗?RPC 的思维方式更贴近业务代码的编写习惯。
2. 性能差距是真实存在的
先说结论:RPC 通常比 HTTP/1.1 快。
为什么?
第一,序列化方式不同。HTTP/1.1 传 JSON 是常态,文本格式,可读性好但体积大、解析慢。RPC 一般用 Protobuf、Thrift 这类二进制序列化协议,数据体积小,解析速度飞快。
第二,HTTP/1.1 有个著名的"队头阻塞"问题------同一个连接上,上一个请求没处理完,下一个就得等着。虽然浏览器用多连接缓解了这个问题,但在微服务高并发场景下,这就是实实在在的性能损耗。
RPC 框架通常会基于 HTTP/2.0 做多路复用,一个连接上可以同时跑多个请求,彻底解决了队头阻塞。
当然,你可能会说:"那 HTTP/2.0 也有多路复用啊,直接用 HTTP/2.0 不就行了?"
理论上可以。但 HTTP/2.0 出现得晚了(2015 年才正式发布),而 RPC 生态(Dubbo 2011 年就开源了,gRPC 2016 年)在它之前就已经在企业内部大规模使用了。历史惯性和生态成熟度摆在那里,不是说换就换的。
3. 传输层灵活度不一样
HTTP/1.1 和 HTTP/2.0 底层只能跑在 TCP 上,没得选。
RPC 框架就灵活多了。gRPC 基于 HTTP/2.0,Dubbo 默认走 TCP 但可以切 HTTP,Thrift 支持 TCP/HTTP/甚至自定义协议。
这意味着 RPC 框架可以根据场景选择最优的传输方式------内网环境追求极致性能就走 TCP 二进制协议,需要跨语言跨网络就走 HTTP/2.0。
历史分工:B/S vs C/S
这是个有意思的历史视角。
以前大家习惯这么划分:
- HTTP → B/S 架构(Browser/Server),浏览器访问网页,天然就是 HTTP。
- RPC → C/S 架构(Client/Server),APP 客户端跟后端服务通信,自己定协议,RPC 更灵活。
现在这个边界已经模糊了。浏览器也能通过 gRPC-Web 调 RPC,后端 Go 服务也能暴露 HTTP 接口。但在微服务内部通信这个场景下,RPC 依然是绝对主流。
现在的实际玩法:对外 HTTP,对内 RPC
这才是重点。现代大型系统的架构基本长这样:
浏览器 / APP
│
▼
┌──────────────┐
│ API 网关 │ ← 对外暴露 HTTP/REST
└──────┬───────┘
│
┌────┴────┐
▼ ▼
┌─────┐ ┌─────┐
│用户 │ │订单 │ ← 微服务之间用 RPC 通信
│服务 │◄─┤服务 │ (gRPC / Dubbo / OpenFeign)
└─────┘ └─────┘
对外用 HTTP:浏览器只认这个,而且 RESTful 接口对前端友好,文档好写,调试方便。
对内用 RPC:性能高、调用方便、服务治理能力强(负载均衡、熔断、限流,Dubbo 这些东西都是标配)。
一张表总结
| HTTP | RPC | |
|---|---|---|
| 本质 | 应用层传输协议 | 远程调用思想/框架 |
| 面向 | 资源(RESTful) | 动作(方法调用) |
| 数据格式 | 通常是 JSON/XML(文本) | 通常是 Protobuf/Thrift(二进制) |
| 性能 | HTTP/1.1 有队头阻塞 | 更高效,多路复用 |
| 底层传输 | 仅 TCP | TCP / UDP / HTTP / 自定义 |
| 代表实现 | --- | gRPC、Dubbo、Thrift、OpenFeign |
| 典型场景 | 浏览器-服务器、对外 API | 微服务内部通信 |
最后
HTTP 和 RPC 不是对立的,甚至不应该拿来比较,但是面试官就是会问这个问题。
HTTP 负责搞定外部世界------浏览器、第三方、开放 API,它是互联网的通用语言。
RPC 负责搞定内部世界------微服务之间高性能、低心智负担地互相调用,它是分布式系统的神经系统。
理解了这层关系,以后面试再被问到这个问题,你心里就有底了。
我是小饼干,专注写点我们都看得懂的技术内容。觉得有用的话,点个赞再走。