让接口重试更安全:超时预算、退避与幂等
让接口重试更安全:超时预算、退避与幂等
在分布式系统中,接口超时并不等于请求失败。服务端可能已经完成写入,只是响应在网络中丢失;也可能仍在排队,稍后才会执行。如果客户端看到超时就立刻重试,原本偶发的网络抖动可能演变成重复扣款、重复创建资源或流量雪崩。因此,重试必须和超时预算、幂等设计及限流策略一起考虑。
一、先确定调用的总时间预算
每次调用都应有明确的截止时间,而不是让连接无限等待。可以把总预算拆成连接、请求处理和重试三个部分。例如一个页面最多允许等待三秒,首次请求可用一秒,第二次重试也用一秒,剩余时间用于网络传输和页面降级。
下游服务收到请求后,也应继续传递剩余截止时间。这样调用链越深,服务越能及时停止没有价值的工作,避免上游已经放弃,数据库和线程池仍在消耗资源。
二、只重试真正的临时故障
连接重置、网关暂时不可用、限流和部分五百错误通常可以重试;参数错误、鉴权失败、资源不存在等确定性错误不应重试。判断依据要来自错误类型和业务语义,不能简单地把所有非二百响应放进同一个循环。
对于限流响应,还应优先读取服务端给出的等待时间。若服务端没有提示,再采用指数退避,例如一百毫秒、二百毫秒、四百毫秒,并加入随机抖动,防止大量客户端在同一时刻再次发起请求。
三、用幂等键阻止重复副作用
创建订单、发送通知或申请云资源都可能产生副作用。客户端应为一次业务意图生成稳定的幂等键,并在所有重试中复用它。服务端把幂等键与请求摘要、处理状态和最终结果保存起来。
第一次请求负责执行;后续相同请求若仍在处理中,可以返回处理中状态;若已经成功,则直接返回之前的结果。如果相同幂等键对应的请求参数不同,应拒绝处理,避免错误复用。
幂等记录要有合理的保留期限。期限过短会让晚到的重试再次执行,期限过长则会增加存储成本。应根据客户端最大重试窗口、消息延迟和业务审计要求共同确定。
四、限制重试放大效应
如果调用链中的每一层都重试三次,三层服务最坏可能把一次用户请求放大为二十多次下游调用。更稳妥的做法是在最了解失败语义的一层重试,并为每个请求设置最大尝试次数。
同时使用并发限制和熔断器。当下游持续失败时,熔断器短暂拒绝新请求,让系统恢复;当排队长度超过阈值时,优先返回明确的繁忙响应,而不是把所有请求堆在线程池里。
五、让重试过程可观测
日志至少记录请求编号、幂等键、尝试次数、剩余预算、错误类型和最终状态。指标应区分首次成功、重试成功、预算耗尽和永久失败。只有把重试次数与下游延迟、错误率放在一起观察,才能判断重试是在提升成功率,还是正在掩盖故障并增加压力。
可靠的接口不会承诺网络永远稳定,而是确保同一业务意图在超时、重试和进程重启后仍只产生一次结果。明确预算、识别临时故障、实现幂等,再配合退避、限流和观测,才能让重试成为恢复机制,而不是新的故障来源。
- 点赞
- 收藏
- 关注作者
评论(0)