网络 HTTP稳定性

超时和重试的三条纪律,救过我不止三次

调外部接口的系统,迟早会遇到三种经典事故:对方挂了把我们拖死、对方抖动我们把重试打成了洪水、对方恢复了我们还在熔断。复盘下来,根子都在超时和重试没定好纪律。

纪律一:任何外部调用必须有超时。连接超时(对方不接电话)和读取超时(接了电话不说话)要分开配,前者短(3~5 秒),后者按对方正常 P99 放 2~3 倍。没有超时的调用等于"永远在等"——线程一个个挂上去,池子耗尽,整个服务陪葬。

纪律二:重试必须带退避和上限。对方响应慢,立刻原速重试就是把一次故障放大成三次请求。指数退避(1s、2s、4s…)加抖动,最多重试 2~3 次,然后放弃并上报。另外,只有幂等操作才能自动重试——下单类接口盲目重试就是重复下单,重试策略要和幂等设计配套。

纪律三:连续失败要熔断。对方持续超时时,继续按比例重试是给对方续命也是给自己放血。简单做法是失败率统计:最近 N 次失败率超阈值就直接快速失败一段时间(半开探测恢复)。不用上来就引熔断框架,一个原子计数器加时间窗就能做基础版。

整体链路示意
整体链路示意

三条纪律的共同点是:都不指望对方靠谱,只约束自己的行为。分布式世界里,外部依赖的故障是常态,把这些纪律写进封装层的默认行为,比每次出事临时补要便宜太多。

顺手检查你项目里的 HTTP 客户端:超时设了吗?重试退避了吗?失败统计有吗?三个都有的,可以关掉这篇了。