一次 RPC 调用要经过哪些环节?超时与重试要注意什么?

结论先行:一次 RPC 调用从客户端发起到拿到结果,要经过动态代理封装、序列化、服务发现与负载均衡、网络传输、服务端反序列化与反射调用、结果返回等环节。工程上最容易出问题的是超时与重试:超时要分层设置,重试只对幂等接口安全,且要有限次、带退避,否则一次故障会演变成雪崩。

一、调用链路各环节

  1. 客户端通过动态代理生成接口的远程调用 stub;
  2. 组装请求:方法、参数序列化(JSON/Protobuf/Hessian),附加调用元数据;
  3. 服务发现:从注册中心拿到可用服务实例列表,负载均衡选一台(随机/轮询/一致性哈希);
  4. 连接管理:从连接池取连接发送请求,同步等待或异步回调;
  5. 服务端接收:反序列化请求,按服务名与方法路由到实现类反射执行;
  6. 返回结果:结果序列化回传,客户端反序列化后返回给调用方或抛出异常。
  • 补充:服务端处理完成但响应在网络中丢失时,客户端同样表现为超时,此时查询业务结果比盲目重放更安全。

二、超时与重试的注意点

关注点说明
超时分两类连接超时(建连阶段)与读超时(等待响应),要分别配置
超时阈值客户端超时要覆盖服务端正常处理时间,过短会误杀慢请求
重试前提只有幂等接口才能安全重试,写接口必须带幂等键
重试策略限次数 + 指数退避 + 随机抖动,避免重试风暴
与熔断配合下游故障时优先快速失败与熔断,而不是无限重试放大压力
超时传递全链路超时要收敛:调用方超时大于等于被调方超时,避免层层叠加
结果语义超时不等于失败,需用幂等键查业务状态后再决定是否重试

三、配置示意

# RPC 客户端常见配置
timeout: 3000            # 读超时 3 秒
connect-timeout: 1000    # 连接超时 1 秒
retries: 2               # 最多重试 2 次,且仅幂等接口开启
backoff: 200             # 重试间隔基数,建议指数退避并加随机抖动

常见追问 / 记忆点

  • 追问:接口不幂等时重试怎么办?答:调用方生成请求幂等键透传,服务端按幂等键去重,重试才会安全。
  • 追问:为什么重试要加抖动?答:同时失败的服务会同时重试,形成毛刺流量,加随机抖动让重试错开。
  • 追问:下游一直超时,重试还是熔断?答:短时抖动可重试,持续故障应熔断并降级,避免雪崩。
  • 记忆点:代理、序列化、发现、传输、反射五环节;超时分层、重试限次、幂等才重试。
笔记加载中…