当重试导致QPS翻倍时,如何防止下游服务雪崩?
解读
在国内高并发互联网场景(如电商大促、春晚红包、秒杀),重试风暴是引发雪崩的首要元凶。一次用户请求因超时触发重试,Agent 系统若不做隔离,会瞬间把 1×QPS 放大到 2×、4×甚至 8×,直接打满下游核心服务(库存、订单、支付),造成级联故障。面试官想考察的是:你能否在“不丢核心成功率”的前提下,用工程手段把重试流量削峰、限流、降级,并具备可观测与自适应能力,最终让系统回到稳态。
知识点
- 重试策略:指数退避 + 随机 jitter + 最大重试次数(通常≤2)。
- 熔断器(Circuit Breaker):失败率阈值 50%、窗口 10s、半开探测 1 请求,国内主流用 Sentinel 或 Hystrix。
- 自适应限流:基于利特尔法则计算最大并发度,动态调整 Agent 的 outbound QPS,阿里 Sentinel 的“BBR 限流”是落地标杆。
- 请求去重与幂等:在网关层统一生成UUID 幂等键,下游 Redis 做 1min 幂等窗口,防止重复写。
- 多级降级:Agent 内部先降级到只读缓存(Redis/Mongo 二级缓存),再降级到静态兜底文案,保证核心链路“可浏览、可下单、可支付”三级体验。
- 优先级队列:把重试流量标记为低优先级,在 Envoy Sidecar 用本地队列权重让新流量优先,防止老请求“饿死”新请求。
- 观测与反馈:Prometheus + Grafana 监控“重试放大系数”(Retry Amplification Ratio),超过 1.5 就触发钉钉/飞书 on-call,并自动扩容 Pod。
答案
“我会把防雪崩拆成四道防线,确保重试 QPS 翻倍时下游仍稳如磐石。
第一道客户端自适应限流:在 Agent SDK 里内置令牌桶 + BBR 感知,实时采集下游 RT 与错误率,一旦检测到下游线程池排队长度 > 200 或错误率 > 10%,立刻把本机 outbound QPS 压到理论最大吞吐的 60%,把重试请求也纳入限流统计,杜绝“重试绕开限流”的误区。
第二道熔断与退避:采用失败率熔断器,窗口 10s、阈值 50%,熔断后直接返回缓存兜底数据或友好文案,不再重试;同时退避策略用指数抖动(200ms、400ms、800ms + 0~50% 随机),避免惊群效应。
第三道服务端优先级调度:在 Kubernetes 集群给下游服务配双队列:高优队列处理新用户请求,低优队列处理重试请求,Sidecar 用权重 4:1 调度;并开启HPA 基于队列长度扩容,10s 内可把 Pod 数翻倍,压测验证重试流量高峰时 P99 延迟上涨不超过 20%。
第四道观测与自愈:通过OpenTelemetry 把“重试放大系数”埋点打到 Prometheus,系数 >1.5 就触发钉钉机器人通知,并自动执行预案脚本:降级非核心接口、扩容副本、提升缓存 TTL;30s 内系数回落即回滚,形成闭环自愈。
上线前用ChaosMesh 做故障演练,模拟下游 30% 节点宕机,重试放大到 3×QPS,系统仍保持成功率 ≥99.5%、P99 ≤500ms,满足国内大厂 SLA。”
拓展思考
-
如果下游是第三方外部接口(如物流、支付),你无法改代码,如何在不伤害成功率的前提下把重试放大系数压到 1.2 以内?
答:在 Agent 侧做外部接口代理层,引入全局令牌桶 + 自适应窗口,并把重试请求合并为批量查询(如物流轨迹批量接口),降低真实 outbound QPS;同时用缓存预拉 + Webhook 推送替代轮询重试。 -
当 Agent 本身是大模型推理服务,每次重试都要重新跑一遍 175B 模型,成本极高,如何权衡重试与成本?
答:把大模型推理拆成可缓存子图,对确定性子结果做Redis 缓存 5min;重试时只重跑失败子图,并用早期退出(Early Exit)把 175B 模型降级到 6B 小模型,成本下降 70% 同时保证业务成功率 ≥99%。