HTTP 与 RPC 经常被放在一起比较,但它们不是同一层的概念:HTTP 是应用层传输协议,规定报文怎么写;RPC 是一种”远程方法调用”的语义抽象,规定调用怎么组织。一个 RPC 框架完全可以用 HTTP/2 当传输层——gRPC 就是这么做的。本文从两者各自解决的问题出发,讲清差异落在哪里,以及微服务选型怎么选。

它解决什么问题

假设服务 A 要调用服务 B 的”查询用户”功能。最原始的办法是自己拿 TCP 写:建立连接、把方法名和参数拼成字节流发出去、解析返回。但 TCP 只保证字节可靠到达,不管消息边界——连发两次请求,对端收到的可能是一段粘连的字节流,拆包、编码、超时、错误码全要自己处理。

HTTP 解决的是”报文格式”问题:请求行、Header、Body、状态码,一套通用格式让所有语言、所有中间设备都能看懂。用 HTTP 完成远程调用完全可行,写一个 GET /users/1001 就能拿到数据。

RPC 解决的是更高一层的”调用体验”问题:让跨进程的调用在代码里看起来和本地方法调用一样。业务方写的是 userService.getUser(1001),底下的网络通信、序列化、寻址、超时重试都被框架收走了。所以正确的问法不是”HTTP 和 RPC 谁取代谁”,而是”这次远程交互,我要自己组织一切,还是要一套封装好的调用体系”。

核心原理

HTTP:围绕资源的通用协议

HTTP 的心智模型是资源访问:URL 定位资源,方法(GET/POST/PUT/DELETE)表达动作,状态码汇报结果。这套模型天然适合开放场景——浏览器、curl、Postman、网关都能直接参与,接入方看文档就能调。

RPC:围绕方法的调用模型

RPC 的心智模型是方法调用:调用方关心的是服务名、方法名、入参、返回值。框架通过客户端代理(Stub)屏蔽网络细节,通常还捆绑了:

  • IDL 与代码生成:用 .proto 或 Thrift 文件定义接口契约,生成各语言的客户端/服务端代码,字段类型在编译期就锁死。
  • 序列化:默认走 Protobuf、Thrift 这类二进制格式,比 JSON 体积小、解析快。
  • 连接管理:内建连接池与多路复用,不必每个调用都新建 TCP 连接。
  • 服务发现:对接注册中心(Nacos、ZooKeeper 等),调用方写服务名而不是 IP 列表。

深入机制

RPC 框架跑在什么之上

RPC 是调用语义,不是传输协议,所以承载方式很自由:

  • gRPC:跑在 HTTP/2 之上。借助 HTTP/2 的帧、流、多路复用,一条 TCP 连接上可并发多个调用,还原生支持 Unary、服务端流、客户端流、双向流四种模式。注意 gRPC 的 HTTP 状态码通常恒为 200,真正的调用结果在 Trailers 的 grpc-status 里——排查时只看 HTTP 状态码会被骗。
  • Dubbo:经典模式是私有协议走 TCP(Dubbo 协议),Dubbo 3 的 Triple 协议则转向 HTTP/2,以便穿透网关和标准化。
  • REST + HTTP:严格说也是一种”远程调用”,只是没有框架替你封装代理、契约与治理,一切自己拼。

序列化与契约的差异

HTTP + JSON 的优势是可读、通用、好调试;代价是文本解析开销大、契约松散——字段改名、类型变化往往要到运行时才暴露。RPC 框架用 IDL 把契约硬化:接口变更会直接打破代码生成或编译,问题左移到开发期。但契约硬不等于免维护,字段增删、枚举演进仍需遵守兼容性规则。

服务治理才是 RPC 的主战场

内部服务数量上来之后,真正耗人的不是”发请求”,而是超时怎么设、失败要不要重试、下游挂了怎么降级、一次请求穿过了哪几个服务。RPC 框架把这些能力(超时、负载均衡、熔断降级、链路追踪、调用统计)做成了调用链路的标准件。HTTP 阵营也能做,但要靠网关、SDK、Service Mesh 自己组合补齐。

对比与权衡

维度 HTTP / REST RPC 框架(Dubbo、gRPC)
概念层级 应用层传输协议 远程调用语义抽象(可跑在 HTTP/2 上)
心智模型 资源 + 动词 服务 + 方法
契约强度 松散,靠文档约定 IDL 强契约,编译期约束
序列化 多为 JSON,可读性好 多为二进制(Protobuf 等),体积小、解析快
连接管理 需自建连接池/复用策略 内建连接池与多路复用
服务发现 需借助网关/注册中心自己组装 通常内建注册发现与负载均衡
调试与生态 浏览器、curl、网关全通吃 二进制报文调试成本高,gRPC 还需网关支持 HTTP/2 Trailers
典型场景 对外开放 API、低频内部调用 内部微服务高频互调、流式调用

工程实践

  • 对外一律 HTTP:浏览器、App、第三方接入,通用性压倒一切。对外接口最怕对方接不动。
  • 对内看规模:服务少、调用频率低、团队没有注册中心和 IDL 维护能力时,HTTP + 网关 + 统一错误码完全够用,强上 RPC 是负资产。服务多、调用链长、对超时重试和链路追踪要求高时,RPC 框架能省掉大量重复建设。
  • 选 gRPC 前想清楚:浏览器端需要 gRPC-Web 或代理;链路上的 LB、网关、Mesh 必须正确处理 HTTP/2 Trailers,否则故障很隐蔽;线上排查二进制报文的成本要提前评估。
  • 性能别背口号:”RPC 一定比 HTTP 快”不成立。HTTP/2 + 连接复用 + 压缩之后差距会缩小,真实结果取决于序列化方式、数据量与部署环境,用自己的接口压测才有结论。

面试视角

有了 HTTP 为什么还要 RPC?

HTTP 只定义报文格式,不解决调用组织问题。RPC 把序列化、服务发现、连接管理、超时重试、负载均衡封装成”像调本地方法一样”的调用体系,在内部微服务高频互调时显著降低重复成本。

gRPC 基于 HTTP/2,为什么说它是 RPC?

RPC 是调用语义而非传输协议。gRPC 用 HTTP/2 做传输承载,用 Protobuf 定义契约和序列化,用代理+代码生成提供方法调用体验——传输层选了 HTTP/2,不妨碍它上层是 RPC 模型。

REST 和 RPC 互斥吗?

不互斥。REST 偏资源建模,RPC 偏方法调用,实践中经常混用:对外接口走 REST,内部服务互调走 RPC。

有了 HTTP/2 还需要 RPC 框架吗?

需要。HTTP/2 提供了多路复用、头部压缩等传输能力,但不替你定义接口契约、生成代码、做服务发现和调用治理——这些恰是 RPC 框架的核心价值。

小结

  • HTTP 是传输协议,RPC 是调用语义抽象,两者不在同一层,不存在谁取代谁。
  • RPC 框架可跑在私有 TCP 协议或 HTTP/2 之上;gRPC 基于 HTTP/2,但真正的调用结果在 Trailers 而非 HTTP 状态码。
  • 真实差异落在序列化效率、契约强度、连接管理与服务治理,而不是一句”RPC 更快”。
  • 选型看调用关系:对外用 HTTP,对内看规模与治理需求,已有成熟 HTTP 基建就不必强上 RPC。