3. RPC 基础原理:RPC 模型、序列化与反序列化、网络传输协议(TCP/HTTP)、动态代理
在支付订单系统中,RPC(Remote Procedure Call,远程过程调用)是微服务间同步通信的核心手段。理解 RPC 的基础原理,是后续选型与调优的前提。本节从 RPC 模型、序列化、网络传输与动态代理四个维度展开。
3.1 RPC 调用模型
RPC 的核心目标是让开发者像调用本地方法一样调用远程服务。其完整调用链路包含 5 个角色:客户端、客户端 Stub、网络传输层、服务端 Stub、服务端。
关键流程: 客户端调用本地 Stub → Stub 将方法名、参数序列化为二进制 → 通过网络传输到服务端 → 服务端 Stub 反序列化 → 调用实际服务方法 → 结果序列化返回。
3.2 序列化与反序列化
序列化是将内存中的对象转换为二进制字节流的过程,反序列化则是逆过程。在支付订单系统中,序列化性能直接影响 TPS(每秒事务处理数)。
3.2.1 常见序列化协议对比
| 序列化协议 | 数据格式 | 空间效率 | 时间效率 | 跨语言 | 典型场景 |
|---|---|---|---|---|---|
| JSON | 文本 | 低(冗余大) | 中 | 是 | HTTP API、调试 |
| Protobuf | 二进制 | 高(压缩比高) | 高 | 是 | 高性能 RPC(gRPC) |
| Thrift | 二进制 | 高 | 高 | 是 | 跨语言服务框架 |
| Hessian | 二进制 | 中 | 中 | 部分 | Java 生态 RPC |
| Java 原生 | 二进制 | 低 | 低 | 否 | 仅限 Java 内部 |
支付场景建议: 订单核心链路(创建、支付、退款)推荐使用 Protobuf 或 Thrift,以降低序列化延迟和带宽消耗。非核心查询场景可降级为 JSON 以方便调试。
3.2.2 序列化性能指标
- 序列化时间: 对象 → 字节流的 CPU 耗时,直接影响 RPC 调用延迟。
- 反序列化时间: 字节流 → 对象的 CPU 耗时,服务端处理瓶颈常在此处。
- 压缩比: 序列化后字节数 / 原始对象大小,影响网络带宽占用。
- 兼容性: 字段新增/删除是否影响旧版本客户端,对支付系统灰度发布至关重要。
3.3 网络传输协议:TCP vs HTTP
RPC 框架的底层传输协议通常选择 TCP 或 HTTP。两者在连接模型、性能、穿透性上存在显著差异。
| 对比维度 | TCP 协议 | HTTP 协议 |
|---|---|---|
| 连接模型 | 长连接,连接复用 | 短连接 / 长连接(HTTP/1.1 Keep-Alive) |
| 传输效率 | 高,无冗余头部 | 低,HTTP 头部开销大 |
| 穿透性 | 差,防火墙可能拦截 | 好,默认 80/443 端口 |
| 协议复杂度 | 需自定义协议编解码 | 标准协议,生态丰富 |
| 典型 RPC 框架 | Dubbo(默认)、Thrift | gRPC(HTTP/2)、Spring Cloud(HTTP) |
选型注意: 支付订单系统内部服务间调用(高并发、低延迟)优先选择 TCP 长连接 协议;对外暴露的 API 网关或跨网络调用,建议使用 HTTP/2 以兼顾穿透性与性能。
3.4 动态代理
动态代理是 RPC 框架实现“透明远程调用”的关键技术。客户端通过动态代理生成接口的代理对象,代理对象内部封装了序列化、网络传输、反序列化等细节,对调用方完全透明。
3.4.1 动态代理实现方式
- JDK 动态代理: 基于接口,使用
java.lang.reflect.Proxy和InvocationHandler。仅支持接口代理。 - CGLIB 动态代理: 基于类继承,使用字节码增强技术。可代理普通类,性能略高于 JDK 代理。
- Javassist: 直接操作字节码,性能极高,常用于框架底层。
3.4.2 动态代理在 RPC 中的工作流程
// 伪代码:RPC 客户端动态代理核心逻辑
public class RpcProxyInvocationHandler implements InvocationHandler {
private final Class<?> interfaceClass;
private final String serviceAddress;
public RpcProxyInvocationHandler(Class<?> interfaceClass, String serviceAddress) {
this.interfaceClass = interfaceClass;
this.serviceAddress = serviceAddress;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 1. 构建 RPC 请求对象(方法名、参数类型、参数值)
RpcRequest request = new RpcRequest();
request.setInterfaceName(interfaceClass.getName());
request.setMethodName(method.getName());
request.setParameterTypes(method.getParameterTypes());
request.setParameters(args);
// 2. 序列化请求对象(例如使用 Protobuf)
byte[] requestBytes = Serializer.serialize(request);
// 3. 通过 TCP/HTTP 连接发送到服务端
byte[] responseBytes = Transport.send(serviceAddress, requestBytes);
// 4. 反序列化响应对象
RpcResponse response = Serializer.deserialize(responseBytes, RpcResponse.class);
// 5. 返回结果或抛出异常
if (response.getException() != null) {
throw response.getException();
}
return response.getResult();
}
}
// 客户端使用示例
OrderService orderService = RpcProxyFactory.create(OrderService.class, "192.168.1.100:20880");
Order order = orderService.getOrderById("20250315001"); // 透明远程调用