# 稳定性工程与故障复盘 > 稳定性不是「不出故障」,而是**故障影响可控、恢复可预期、同类问题不重复**。它靠指标定义、防护设计与复盘机制,不靠英雄主义。 ## 一、把可用性变成数字 | 可用性 | 年停机 | 月停机 | | --- | --- | --- | | 99% | 约 3.65 天 | 约 7.2 小时 | | 99.9% | 约 8.76 小时 | 约 43 分钟 | | 99.99% | 约 52 分钟 | 约 4.3 分钟 | 关键点:**可用性是链路的乘积**。一个接口依赖 5 个 99.9% 的服务,串联可用性约 99.5%,已经掉到 3.6 天/年。要么减少串行依赖,要么给关键依赖做冗余与降级。 ### SLI、SLO 与错误预算 - SLI:实际测量值(成功率、P99、错误率); - SLO:目标(如「99.9% 的请求在 300ms 内成功」); - 错误预算:允许的失败量(0.1%)。预算烧完,优先做稳定性而不是新功能。 没有 SLO 的稳定性工作会变成「谁喊得响谁优先」。 ## 二、六种典型故障模式 | 模式 | 表现 | 触发原因 | | --- | --- | --- | | 单点 | 一个实例/机房挂掉全站不可用 | 无冗余、配置错误 | | 雪崩 | 下游慢导致上游线程耗尽,逐层崩 | 无超时/无隔离 | | 重试风暴 | 故障时重试放大流量,越重试越挂 | 无退避、无重试预算 | | 惊群 | 缓存失效瞬间全量打到数据库 | 缓存同一时刻过期 | | 级联超时 | 超时设置逐层放大,最后全链路超时 | 超时预算不匹配 | | 慢查询拖垮连接池 | 个别慢 SQL 占满连接 | 无慢查询治理、池过小 | ## 三、五类防护手段 | 手段 | 作用 | 关键细节 | | --- | --- | --- | | 超时 | 切断无意义等待 | 每层超时必须小于上游预算;下游超时之和不能超过上游 | | 重试 | 应对瞬时失败 | 指数退避 + 抖动;只对幂等操作重试;设置重试预算(如不超过请求量的 10%) | | 熔断 | 快速失败,保护调用方 | 基于错误率与慢调用比例;半开探测;熔断后要有降级返回 | | 限流 | 保护自己 | 令牌桶控制速率、漏桶整形;按调用方配额,避免单租户打满 | | 隔离 | 限制爆炸半径 | 线程池/连接池按依赖隔离(舱壁),避免一个慢依赖拖死全部 | | 降级 | 有损可用 | 返回缓存/默认值/精简结果,并在响应里打标 | 降级的难点不是技术,是**产品与业务的共识**:哪些功能可以暂时不要。这必须在故障前谈好,故障时没时间讨论。 ## 四、可观测性:没有数据就没有稳定性 - **指标**:四黄金信号(延迟、流量、错误、饱和度),按服务与依赖维度看; - **日志**:结构化、带 traceId、可检索;重点是错误日志与关键状态变更; - **追踪**:跨服务链路,能回答「这次慢在哪一跳」; - **告警**:基于症状(用户受影响)而不是原因(CPU 高);有分级与值班路径,避免告警疲劳。 ## 五、演练:把故障提前演练一遍 1. **依赖故障**:人为让下游超时/报错,验证熔断与降级是否生效; 2. **容量演练**:按峰值的 1.5 倍压测,验证扩容与限流; 3. **发布回滚**:演练一次完整回滚,计时; 4. **数据恢复**:从备份恢复一次,确认备份真的可用; 5. **值班演练**:让不熟悉系统的人按预案处理,暴露文档缺陷。 演练的价值在于**发现「以为有」其实没有的能力**:以为有降级、以为能回滚、以为备份可用。 ## 六、复盘:从事故到机制 复盘的目标不是追责,而是**让同类事故不再发生**。一份合格复盘包含: - **时间线**:何时发现、何时响应、何时恢复,精确到分钟; - **影响面**:多少用户、多少请求、是否涉及资金与合规; - **根因**:技术根因 + 流程根因(为什么没提前发现); - **处置**:止血动作与恢复动作分开写; - **行动项**:每条有负责人、截止时间、验收方式,且区分「立刻做」「排期做」「不做了(说明理由)」。 最常见的失败复盘是:行动项只有「加强监控」「提高意识」。这类项无法验收,等于没做。 ## 七、自检清单 - [ ] 核心接口有 SLO,且团队知道错误预算还剩多少 - [ ] 每个外部依赖都有超时、重试策略与降级方案 - [ ] 关键依赖做了隔离,慢依赖不会拖死主链路 - [ ] 告警基于用户影响,且有分级与值班安排 - [ ] 最近半年做过故障演练与回滚演练 - [ ] 复盘有行动项闭环,能查到完成情况 - [ ] 我知道系统最脆弱的三个点,以及各自的爆炸半径