说说 HTTP 和 RPC 的区别?
结论先行:HTTP 是协议,RPC 是调用范式。RPC 指「像调本地方法一样调远程服务」,它可以用 HTTP 承载(gRPC、Feign),也可以用自定义 TCP 协议承载(Dubbo);HTTP 则规定了报文格式与语义(方法、状态码、头、体)。所以「HTTP vs RPC」严格说是「通用文本协议 vs 面向方法的远程调用」,比较的是两种通信风格而非同一层概念。
1. 概念关系
RPC(远程过程调用范式)
├── 基于 HTTP:gRPC(HTTP/2)、Feign(HTTP/1.1)、JSON-RPC
└── 基于 TCP:Dubbo 协议、Thrift、自定义二进制协议
HTTP(应用层协议)
├── RESTful API(资源风格)
└── 作为 RPC 的传输层(上面两种)
面试里问「HTTP 和 RPC 的区别」,实际想问的是 RESTful HTTP 调用 与 二进制 RPC 框架 的差异。
2. 关键差异
| 维度 | HTTP + REST | 二进制 RPC(Dubbo/gRPC) |
|---|---|---|
| 交互模型 | 资源 + 动词(GET/POST/PUT/DELETE) | 接口 + 方法 |
| 报文 | 文本头 + JSON/XML | 紧凑二进制头 + 二进制体 |
| 序列化 | JSON(可读、体积大) | Protobuf/Hessian2(紧凑、快) |
| 连接 | HTTP/1.1 短连接或 keep-alive;HTTP/2 多路复用 | 长连接 + 请求多路复用 |
| 服务治理 | 依赖网关/注册中心/客户端封装 | 框架内建(路由、超时、重试、熔断) |
| 跨语言 | 天然支持 | 取决于 IDL 与协议(gRPC 强) |
| 调试 | curl/Postman 直接调 | 需要 IDL、专用工具或泛化调用 |
| 契约 | OpenAPI 文档 | IDL(.proto/.thrift)编译期校验 |
| 性能 | 一般(文本解析、头开销) | 高(二进制、连接复用) |
3. 一次调用的开销拆解
REST/JSON:
序列化 JSON(50μs) → 拼 HTTP 头(10μs) → TCP 发送 → 服务端解析头+JSON(60μs) → 反序列化
Dubbo/Hessian2:
序列化二进制(20μs) → 拼协议头(5μs) → TCP 发送 → 服务端解协议头+反序列化(25μs)
差距主要来自三处:文本解析、头部体积、序列化效率。在局域网内这些差距是微秒级,除非 QPS 极高或报文很大,否则业务逻辑与数据库才是瓶颈。
4. 代码对照:同一个「查库存」
REST(Feign):
@FeignClient(name = "stock-service", path = "/api/stock")
public interface StockClient {
@GetMapping("/{skuId}")
StockDTO get(@PathVariable("skuId") Long skuId);
}
gRPC(IDL 先行):
service StockService {
rpc GetStock (StockRequest) returns (StockReply);
}
message StockRequest { int64 sku_id = 1; }
message StockReply { int64 sku_id = 1; int32 available = 2; }
// 生成 Stub 后调用,方法签名由 IDL 保证
StockReply reply = stockServiceBlockingStub.getStock(
StockRequest.newBuilder().setSkuId(skuId).build());
REST 的契约是文档约定,gRPC 的契约是编译期强制的 IDL——这是两者在团队协作上的核心差别。
5. 选型建议
| 场景 | 选择 |
|---|---|
| 对外开放 API、第三方接入 | REST + JSON |
| 浏览器/移动端直连 | REST(HTTP 缓存、CORS 生态成熟) |
| 内部高频调用、强类型 | gRPC / Dubbo |
| 需要流式传输(大文件、实时推送) | gRPC streaming / WebSocket |
| 已有 Spring Cloud 体系 | Feign(HTTP),必要时局部引入 gRPC |
6. 常见追问
追问一:REST 一定比 RPC 慢吗? 不一定。HTTP/2 + Protobuf 的 gRPC 在性能上可以超过很多自定义 RPC。慢的是「HTTP/1.1 + JSON + 短连接」这套组合。
追问二:HTTP/2 解决了什么问题? 多路复用(一个连接并发多请求)、头部压缩(HPACK)、服务端推送、二进制分帧。它让 HTTP 也能具备 RPC 的长连接复用能力,gRPC 正是构建在 HTTP/2 之上。
追问三:RPC 的「像本地调用」有什么代价? 网络不可靠:超时、重试、幂等、序列化兼容、连接断开都要处理。框架把这些封装起来,但不会消除它们——「远程调用不可靠」这条铁律始终成立。
追问四:为什么内部服务用 RPC 还要网关? 外部流量仍需统一入口做鉴权与限流;RPC 面向内部服务间调用,不直接暴露公网。
追问五:RESTful 的「无状态」和 RPC 的「有状态连接」冲突吗? 不冲突。无状态是应用层约束(每个请求自带上下文),RPC 的长连接只是传输层复用,服务端仍应保持无状态以便水平扩展。
小结
HTTP 与 RPC 的关系是「载体与范式」:HTTP 是通用协议,RPC 是面向方法的调用风格。选型看的是边界(对内/对外)、契约强度(文档/IDL)与性能要求,而不是简单地认为「RPC 更快更高级」。