重试、超时与熔断:分布式调用的三道防线
在单体应用里,方法调用要么成功、要么抛异常,结果是确定的。一旦把系统拆成微服务,网络就成了最不可靠的环节:请求可能丢失、响应可能超时、下游可能缓慢到让你怀疑人生。面对这种不确定性,成熟的做法不是祈祷网络不出问题,而是给每一次远程调用装上三道防线:超时、重试与熔断。
第一道防线:超时,给等待设个期限
没有超时的调用是最危险的。线程池里的一个线程如果永远等一个无响应的下游,积少成多就会把整个线程池耗尽,进而拖垮上游,这就是典型的级联故障。
设置超时要区分连接超时和读取超时:连接超时控制“能不能连上”,一般设得短一些,比如200到500毫秒;读取超时控制“连上之后等多久”,要根据接口的P99耗时来定,通常是正常耗时的两到三倍。一个常见的错误是把所有接口都配成同一个超时值——支付接口和报表导出接口的耗时分布完全不同,一刀切只会让快的变慢、慢的更慢。
第二道防线:重试,失败了可以再试一次
超时之后,最自然的想法是再试一次。但重试不是无脑循环,它有三个前提。第一,被调用的接口必须是幂等的,否则“创建订单”重试三次就可能产生三笔订单。第二,重试要有上限,一般两到三次足够,太多只会放大故障。第三,重试要有退避策略,比如第一次立即重试、第二次等一秒、第三次等两秒,避免所有客户端在同一时刻打爆刚恢复的下游,这就是所谓的“重试风暴”。
还要区分“可重试”和“不可重试”的错误:网络超时、连接拒绝、5xx通常可以重试;4xx参数错误、鉴权失败重试一百次也没用,只会浪费资源。
第三道防线:熔断,下游撑不住就先放手
当下游已经明显故障,比如错误率连续超过一半,继续重试只是在给它“上刑”。熔断器的思路和家里的保险丝一样:检测到异常比例超标,就“跳闸”,直接快速失败,不再发起真实调用;过一段时间进入半开状态,放少量请求过去探路,成功了就闭合恢复,失败了就继续熔断。
熔断和降级经常一起出现:熔断是“不打了”,降级是“换个方式打”——比如返回缓存数据、默认值,或者走异步补偿流程。两者配合,才能在故障时既保护系统,又尽量不影响用户体验。
三道防线如何配合
一个合理的组合是:调用方设置1秒读取超时,加上最多重试2次并带指数退避,再用熔断器监控错误率。正常情况下用户几乎感知不到它们的存在;下游抖动时,重试把偶发失败抹平;下游真正挂掉时,熔断器迅速止损,避免雪崩。可以用Polly、Resilience4j、Sentinel这类现成的库来实现,不必自己造轮子,但一定要理解每个参数背后的含义,否则默认配置在生产环境多半不合适。
总结
分布式系统的稳定性,很大程度上取决于你如何对待失败。超时划定等待的边界,重试消化偶发的抖动,熔断在系统性故障时果断止损。三道防线层层设防,才能让你的服务在不可靠的网络上,依然给出可靠的表现。
- 点赞
- 收藏
- 关注作者
评论(0)