RPC 全称是 Remote Procedure Call,远程过程调用。

客户端代码
   ↓ 调用接口方法(看起来完全是本地调用)
Client Stub(客户端代理)
   ↓ 把“方法名 + 参数”打包(序列化)
网络传输(TCP / HTTP2 等)
   ↓
Server Stub / Skeleton(服务端骨架)
   ↓ 解包(反序列化)→ 找到真正的实现类 → 执行方法
真正的业务实现类
   ↓ 返回结果
Server Stub 把结果打包发回
   ↓
Client Stub 解包结果,返回给调用方

RPC比HTTP更适合内部服务调用
RPC 比 REST 风格的 HTTP 接口更适合内部服务调用,主要有四个原因。第一,RPC 通常使用 Protobuf 等二进制序列化,数据体积更小,序列化速度更快,更适合高频低延迟调用。第二,RPC 使用接口或 IDL 定义强类型契约,很多参数不匹配问题可以在编译阶段发现。第三,RPC 框架通常集成服务注册发现、负载均衡、超时、重试和熔断等服务治理能力。第四,RPC 会把远程调用封装成类似本地方法调用,降低内部服务开发成本。不过 RPC 调试和跨平台开放性不如 REST,所以一般对外使用 HTTP REST,对内使用 RPC。
根本原因是RPC针对服务间高频、低延迟、强契约调用做了专门优化。

  • 使用REST时,调用方需要关心URL、HTTP方法、Header、JSON序列化、状态码、响应体解析,但是使用RPC时,调用方式更接近普通Java方法,例如

    User user = userService.getUserById(1001L);
  • RPC性能通常更高
    REST 接口通常使用JSON:

    {
      "userId": 1001
      "username": "zhangsan"
      "status": "ACTIVE"
    }

    JSON存在几个特点:

    • 字段名会重复传输
    • 本质时文本
    • 需要字符串解析
    • 数据类型表达不严格

    RPC使用Protobuf、Hessian、Thrift等二进制序列化格式
    例如:

    message User{
      int64 user_id = 1;
      string username = 2;
      string status = 3;
    }

    传输时主要使用字段编号1、2、3,不需要反复传输完整字段名。
    所以通常表现为:

    • 数据包更小
    • 序列化速度更快
    • 反序列化速度更快
    • 网络带宽占用更低
    • 高频调用下延迟更小
  • RPC强契约接口
    REST接口经常依赖接口文档约定

    请求:
    {
      "userId": 1001,
      "amount": 99
    }

    调用方可能遇到这些问题:

    • userId到底是数字还是字符串
    • amount是否允许为空
    • status有哪些可选值
    • 字段被改名后,调用方什么时候可以发现

    很多问题要到运行时才暴露
    RPC通常使用Java接口或IDL文件定义契约
    例如gRPC

    service OrderService {
      rpc CreateOrder(CreateOrderRequest)
          return (CreateOrderReply);
    }
    message CreateOrderRequest {
      int64 user_id = 1;
      double amount = 2;
    }

    根据.proto文件生成Java代码后,调用方只能按照规定的类型进行调用:

    CreateOrderRequest request = CreateOrderRequest.newBuilder()
          .serUserId(1001L)
          .setAmount(99.9)
          .build();

    如果错误传入.setUserId("1001"),程序编译阶段就会报错。

    REST:
    接口字段不匹配 → 可能运行时才发现
    
    RPC:
    参数类型不匹配 → 编译阶段就能发现
  • RPC 框架集成了微服务治理能力
  • RPC 更容易支持长连接和多路复用
    传统 HTTP/1.1 场景下,连接管理效率相对有限。

而许多 RPC 框架会使用:

TCP 长连接
连接池
HTTP/2
多路复用
异步请求
流式通信

例如 gRPC 基于 HTTP/2,可以在同一个连接上并发传输多个请求:

同一条连接
├── 请求 A
├── 请求 B
├── 请求 C
└── 请求 D

总的来说:REST 优先解决开放性和通用性,RPC 优先解决内部服务调用的性能、契约和治理问题。

标签:无

你的评论