核心依赖不可用时如何做高可用降级?
简化版
核心依赖不可用时,先判断业务能否在不伪造事实的前提下继续:可读旧数据则带陈旧标识返回,可延后则进入可靠队列,不能安全继续的写操作应明确失败或进入可查询的处理中状态。 同时用超时、熔断、舱壁和重试预算止住资源扩散,并为恢复后的回放、对账和退出降级设计闭环。
详细版
按依赖能力而非整个服务分级。例如商品描述可读缓存,推荐可返回静态榜单,积分可异步补发;库存预占、余额扣减在状态未知时不能假成功。降级响应需携带原因和数据时间,监控独立统计,不可混入正常成功率。
自动触发使用连续窗口的错误率、P99 和资源水位,人工开关带作用域、TTL 和审批。降级期间记录待办和幂等键;依赖恢复后先小流量探测、预热缓存、限速回放,再逐级撤销,防止积压洪峰造成二次故障。
完整版教学
一、先区分“核心依赖”和“不可降级动作”
一个核心服务里的不同接口语义不同。用户中心不可用时,头像读取可用旧缓存,权限校验却可能必须 fail closed。降级设计的判断单位是业务动作及其错误后果,不是服务名或团队等级。
心法:降级可以降低体验和实时性,不能篡改资金、权限、库存等关键事实。
二、四种安全出口
| 出口 | 场景 | 关键约束 |
|---|---|---|
| 旧缓存 | 商品、配置查询 | 最大陈旧度与标识 |
| 静态结果 | 推荐、装饰模块 | 不影响核心决策 |
| 异步受理 | 积分、通知 | 可靠持久化与查询 |
| 明确失败 | 支付、权限未知 | 不伪造成功 |
“返回处理中”必须真的保存了请求状态,并能用 requestId 查询;仅返回一句处理中却没有持久记录,仍会丢业务。
三、先止住级联资源消耗
依赖超时从 100ms 升到 3s 时,线程和连接会快速堆积。调用 timeout 要小于入口剩余 deadline,熔断根据失败/慢比例短路,舱壁限制最多占用资源,重试预算限制额外流量。四者分别解决单次时长、无望调用、并发占用和流量放大。
request -> deadline -> bulkhead -> circuit breaker -> dependency
\-> safe fallback / explicit failure
四、数字判断 fallback 是否真的减压
入口 2000 QPS,依赖容量降到 300 QPS。若熔断前仍放 1000 QPS、每次重试一次,依赖会承受近 2000 次尝试。应将探测和必要请求限制在 300 以下,其余直接走本地 fallback。fallback 不能再次访问同一数据库,否则只是换了调用入口。
旧缓存允许 5 分钟陈旧时,应检查 now-dataAsOf<=5min;超过就明确不可用,而不是无限延长。
五、异步降级的数据闭环
请求先用业务唯一键写入本地事务 Outbox 或可靠队列,再返回 accepted。消费者恢复后幂等处理,失败进入重试和人工队列。若本地持久化也不可用,就不能承诺已受理。
RECEIVED -> PENDING -> PROCESSING -> SUCCESS
\-> RETRY -> MANUAL
状态机让用户查询和运维补偿共享同一事实,不需要靠日志猜测。
六、恢复阶段要防二次冲击
依赖刚恢复时缓存冷、连接未热、积压很多。先半开探测,再 1%、5%、20% 放量;积压回放设置单独限额和优先级。若 60 万条积压净处理速度 1000 条/秒,至少 10 分钟才能清完,这段时间不能把实时和历史流量一起全开。
监控原始依赖失败、熔断拒绝、fallback 类型、缓存年龄、待办积压、回放成功和业务对账差异。降级命中应在状态页或客服链路可查询。
七、常见误区与追问
- 误区:核心依赖不能降级。 有些能力可降实时性或转异步,关键是保持业务语义。
- 误区:统一返回默认值最稳定。 默认值可能被解释为真实余额、库存或权限。
- 误区:fallback 返回 200 就算高可用。 用户得到错误事实比明确失败更危险。
- 误区:依赖恢复后立即全量回切。 冷启动和积压会再次压垮依赖。
- 追问:权限依赖挂了怎么办? 高风险操作通常 fail closed,低风险只读可使用短期签名声明。
- 追问:异步受理如何防丢? 先可靠持久化并返回 requestId,之后幂等消费和对账。
- 追问:怎么判断缓存还能用? 由业务最大陈旧度、版本和权限上下文共同决定。
八、加强记忆
核心依赖降级按“语义判定—资源止血—安全出口—状态留痕—限速恢复”展开。能旧读、能静态、能异步、必须失败四种出口要明确;任何成功承诺都要有事实依据。恢复时同时处理实时流量与历史积压,才算完整高可用方案。