说说 HTTP 和 RPC 的区别?

#Java#面试八股

说说 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 更快更高级」。

笔记加载中…