有了 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 负责搞定内部世界——微服务之间高性能、低心智负担地互相调用,它是分布式系统的神经系统。

理解了这层关系,以后面试再被问到这个问题,你心里就有底了。


我是小饼干,专注写点我们都看得懂的技术内容。觉得有用的话,点个赞再走。

Logo

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构

更多推荐