RPC 超时、重试、幂等怎么一起设计?一次讲清调用失败、重试风暴与下游保护思路
大家好,我是一名有 4 年工作经验的 Java 后端开发。
分布式系统里,很多事故最后都和这几个词有关:超时、重试、幂等。
单看每一个都不难理解,但真正线上出问题时,往往就是它们组合在一起把系统放大的。
这篇文章我想系统聊一聊 RPC 超时、重试和幂等到底应该怎么一起设计。
🦅个人主页
🐼
文章目录
- [RPC 超时、重试、幂等怎么一起设计?一次讲清调用失败、重试风暴与下游保护思路](#RPC 超时、重试、幂等怎么一起设计?一次讲清调用失败、重试风暴与下游保护思路)
-
- 一、为什么这三个一定要一起看
- 二、超时应该怎么定
- 三、重试什么时候该开,什么时候不该开
- 四、幂等为什么是重试前提
- 五、推荐的落地思路
-
- [5.1 超时](#5.1 超时)
- [5.2 重试](#5.2 重试)
- [5.3 幂等](#5.3 幂等)
- [5.4 熔断与降级](#5.4 熔断与降级)
- 六、面试中怎么回答
- 七、总结
- 八、结尾
一、为什么这三个一定要一起看
因为真实线上调用链通常是这样的:
- 下游变慢
- 上游等待超时
- 调用方自动重试
- 下游压力更大
- 幂等没做好,业务还重复执行
这就是典型的重试风暴。
所以:
- 超时决定"等多久"
- 重试决定"要不要再试"
- 幂等决定"重试之后会不会出错"
这三个永远不能分开理解。
二、超时应该怎么定
超时不是越长越稳,也不是越短越安全。
更合理的做法通常是基于:
- 下游正常 RT
- P99
- 链路预算
来定。
比如一个请求总预算 500ms,你不可能把三个下游都配 500ms 超时。
所以超时一定是整条链路预算的一部分。
三、重试什么时候该开,什么时候不该开
我更建议只在这些场景考虑自动重试:
- 短暂网络抖动
- 明确可重试错误
- 幂等操作
而这些场景要特别谨慎:
- 下游已经明显过载
- 写操作但没有幂等
- 多层调用都在重试
因为多层重试最容易放大事故。
四、幂等为什么是重试前提
如果一个调用不能幂等,那自动重试就很危险。
比如:
- 扣库存
- 发优惠券
- 加余额
如果没有幂等保护,重试一次就可能多执行一次。
所以我更建议:
先考虑幂等,再考虑是否重试。
五、推荐的落地思路
5.1 超时
- 按链路预算配置
- 不能无限等
5.2 重试
- 限制次数
- 限制只在特定异常下触发
- 尽量单层重试
5.3 幂等
- 用业务唯一键
- 用状态流转
- 用唯一索引兜底
5.4 熔断与降级
如果下游已经明显不稳,就不要靠重试硬撑。
六、面试中怎么回答
如果面试官问你:
RPC 超时、重试、幂等一般怎么一起设计?
你可以这样回答:
第一,这三个能力是联动设计的。超时决定调用最多等多久,重试决定失败后要不要再试,幂等决定重试之后业务结果会不会出错,所以它们不能拆开看。
第二,超时一般要按整条链路预算去配置,而不是给一个很大的统一超时;重试则应该非常克制,通常只在可重试异常和明确幂等操作下启用,而且尽量避免多层同时重试。
第三,如果一个写操作没有幂等保护,我通常不会轻易开启自动重试。真正线上更稳的做法往往是"合理超时 + 少量重试 + 幂等兜底 + 熔断降级"一起配合。
七、总结
超时、重试、幂等这三个问题,真正难的不是概念,而是它们一旦放到同一条链路里,会彼此放大影响。
如果只记一句结论,我觉得可以记住这句:
重试不是默认正确动作,只有当超时预算合理、错误类型可重试、业务结果可幂等时,重试才真正安全。
八、结尾
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏、关注。
后面我会继续整理一些更偏实战的 Java 后端和分布式系统设计文章,尽量少写空泛概念,多写真实项目里会踩到的坑。