重试
重试用于恢复短暂故障,也会增加下游负载。本文负责错误分类、退避与重试预算。
1. 面试核心
先记住这几条,再读正文- 多层放大。 多层各尝试 3 次时,四层最深调用上界为
3⁴=81次。卡 · 可重试错误 - 退避抖动。 Full jitter 在当前指数退避上限内随机选择等待时间。
- 重试预算。 单请求次数与系统级重试预算共同约束额外负载。
- 服务端等待建议。
Retry-After支持秒数与 HTTP 日期,等待仍需服从总预算。卡 · Retry-After 与剩余预算 - 并行备份请求。 Hedging 并行发送备份请求,消耗额外容量。
2. 可重试错误
短暂连接错误与部分服务端错误可作为候选。参数错误、权限不足和确定性代码错误应直接失败。
是否重试还取决于接口语义与结果是否已提交。超时只能说明结果未知。持续过载时,继续发送会延迟恢复。
3. 写操作重试
写请求需明确重复副作用边界。稳定请求标识与结果恢复见幂等键。
协议声明为幂等的方法,也需实现对应语义。POST 可以通过业务幂等契约支持安全重发。
4. 指数退避
退避上限随失败次数增长,再受 cap 截断。
a = 0 表示第一次重试
backoff = min(cap, base × 2^a)
例如 base 为 100 ms,cap 为 1 s。前三次重试上限为 100、200、400 ms。退避等待也计入请求总预算。
5. 抖动
无抖动退避会使大量客户端同步醒来。Full jitter 从 [0, backoff] 采样等待时间。
实例需避免使用相同随机序列或固定整秒调度。仅有随机等待仍需限制总次数和额外流量。
6. 尝试次数
总尝试 3 次表示首次调用加两次重试。配置与指标应明确是否包含首次调用。
四层各尝试 3 次时,最深调用上界是 3⁴=81。总时限与提前成功会减少实际次数,但过载时仍需防放大。
选择一层承担主要业务重试。其他层仅保留语义明确的局部恢复。
7. 重试预算
单请求上限无法控制全系统额外流量。重试预算可以约束总重试比例或并发数。
例如成功请求补充 retry token,重试消耗 token。错误持续时额度耗尽,请求快速失败。预算按下游或路由统计,避免一个故障耗尽全部配额。
8. Hedged request
Hedging 在首个请求变慢后,并行发送备份请求。它适合有独立副本与额外容量的幂等读取。
首个可接受成功结果返回后,取消剩余尝试。取消仍需下游配合。整体过载时新增备份会进一步消耗容量。
应限制 hedging 比例与并发,并观测真实放大倍数。
9. 故障注入验证
注入 reset、延迟、限流和局部实例故障。分别统计原始请求、attempt、成功率和 P99。
还需检查全体过载时预算是否停止追加请求。关闭重试后若系统恢复,应复查放大路径。取消后的在途数量也属于验收指标。
10. Retry-After 与剩余预算
Retry-After: 2 表示等待 2 秒。HTTP 日期形式表示可以再次尝试的时间点。
客户端将服务端建议与本地退避共同纳入计划。一种策略是至少等待两者较大值,再加入有限抖动。日期形式还需考虑时钟偏差与解析失败。
例如总预算只剩 500 ms,而建议等待 2 秒。此时应结束自动重试,并返回明确结果。为赶 deadline 提前发送会破坏服务端的恢复节奏。
11. 常见问题
11.1 5xx 的重试条件
5xx 只是服务端错误类别。确定性缺陷、资源过载和短暂故障需要分别处理。仅有状态码不足以证明下一次尝试有价值。
11.2 实例切换与副作用
切换实例可绕过局部故障。原实例已提交而响应丢失时,新实例仍需去重。重试安全性依赖业务契约。
12 · 面试题卡片
12.1 为什么重试会形成流量放大,如何控制
出现公司:字节跳动
考察重点
- 理解瞬时与永久错误、幂等和结果未知。
- 理解指数退避、full jitter 与端到端 deadline。
- 理解多层重试乘法和系统级重试预算。
参考回答
多层重试让最深下游的尝试数相乘。
四层各尝试 3 次,上界达到 81 次。下游过载时,额外请求会占用更多资源。
主要重试集中在一层,并限制总尝试数。指数退避与 jitter 分散时间,系统预算约束总量。所有等待与尝试共用 deadline。故障注入时分别统计原始请求与实际 attempt。
12.2 收到 Retry-After: 2,但请求只剩 500 ms,应该怎样处理?
出现公司:暂无已核验的公开来源(本站自测)
考察重点:服务端等待建议与请求总时限。
相关内容:Retry-After 与剩余预算。
参考回答
结束本次自动重试,因为剩余预算无法覆盖建议等待。
Retry-After: 2 表示等待 2 秒。新尝试还需留出执行和返回时间。结果未知的写操作可提供状态查询入口。