稳定性工程:SLO 量化、降级收敛与故障兜底体系
一、从"不能出故障"到"定义可接受的故障量"
1.1 为什么"不能出故障"是一个危险目标
这个目标不可量化(什么叫"故障"?P99 延迟翻倍算不算?),会导致风险厌恶压制创新(最安全的做法是不做任何变更),且无法驱动资源分配(99.9% 和 99.99% 的工程成本差距是 10 倍,值不值得?)。
1.2 Google SRE 框架:SLI → SLO → Error Budget
erlang
体验AI代码助手
代码解读
复制代码
SLI(Service Level Indicator) = 实际度量的指标 例:可用性 = 成功请求 / 总请求 | P99 延迟 | 错误率 ↓ SLO(Service Level Objective) = 对 SLI 设定的目标 例:可用性 ≥ 99.9% | P99 ≤ 300ms | 错误率 < 0.1% ↓ Error Budget(错误预算) = 1 - SLO 例:99.9% SLO → 每月允许 43.2 分钟不可用 → 这是"可消耗的稳定性资源"
Error Budget 的工程意义:它把"稳定性 vs 新功能"的博弈,变成了数据驱动的决策:
| Error Budget 消耗状态 | 发布策略 | 备注 |
|---|---|---|
| < 50% 已消耗 | 🟢 绿灯,正常发布新功能,可进行混沌实验 | 充裕 |
| 50% - 80% 已消耗 | 🟡 黄灯,谨慎发布,暂停混沌实验,加强变更审查 | 注意 |
| > 80% 已消耗 | 🔴 红灯,停止新功能发布,专注稳定性修复 | 危险 |
| 100% 耗尽 | 🚨 危机模式,全员稳定性,SLA 可能违约 | 紧急 |
二、SLO 的正确定义方式:从用户体验而非技术指标出发
2.1 常见错误:用基础设施指标定义 SLO
arduino
体验AI代码助手
代码解读
复制代码
❌ 错误的 SLO: "数据库 CPU 使用率 < 70%" "服务 Pod 重启次数 < 2 次/天" ✅ 正确的 SLO(用户体验视角): "用户提交表单后,P99 在 3 秒内看到确认结果" "支付接口的成功率 ≥ 99.95%"
基础设施指标出问题,用户不一定感知;用户体验指标劣化,一定意味着用户在受苦。
2.2 核心链路分级与 SLO 差异化
| 链路级别 | SLO 目标 | 月允许不可用时间 | 典型功能 |
|---|---|---|---|
| 🔴 核心不可降级 | 99.99% | 4.4 分钟 | 用户登录/认证、支付/核心业务写入、权限变更实时生效 |
| 🟡 重要可短暂降级 | 99.9% | 43.2 分钟 | 数据查询/报表、搜索功能、文件预览 |
| 🟢 可降级 | 99.5% | 3.6 小时 | 推送通知、统计分析数据、AI 推荐功能 |
| ⚪ 尽力而为 | 99% | 7.2 小时 | 审计日志查询、非关键后台任务 |
关键认知:不同链路 SLO 不同,对应的保障策略和降级方案完全不同。把所有功能都追求 99.99% 是资源浪费;核心链路降级是稳定性事故。
三、降级收敛:架构师的核心设计能力
这是本篇最重要的内容。降级不是"出了故障再说",而是一个预先设计好的状态机,每个状态有明确的进入条件、退出条件和用户感知描述。
3.1 降级状态机设计
五个状态的定义:
| 状态 | 用户感知 | 技术描述 |
|---|---|---|
| 正常运行 | 一切正常 | 所有服务健康,SLO 消耗正常 |
| 局部降级 | 部分非核心功能不可用 | 非核心服务错误率 > 5% 或 P99 > SLO 阈值 × 2 |
| 只读模式 | 可以查看,无法操作 | 存储写入不可用,读路径正常 |
| 全面降级 | 仅核心功能可用 | 核心依赖熔断开启,Error Budget 接近耗尽 |
| 服务不可用 | 系统无法使用 | 兜底数据也不可用,需人工介入 |
状态转换规则:
| 触发条件 | 当前状态 → 目标状态 | 触发方式 |
|---|---|---|
| 非核心服务错误率 > 5% 且持续 2min | 正常运行 → 局部降级 | 自动 |
| 核心依赖熔断器开启 | 正常运行 → 全面降级 | 自动 |
| 存储写入不可用 | 正常运行 → 只读模式 | 自动 |
| 错误率 < 1% 且稳定 5min | 局部降级 → 正常运行 | 自动恢复 |
| 写入服务恢复 | 只读模式 → 正常运行 | 自动恢复 |
| 降级范围扩大,核心服务受影响 | 局部降级 → 全面降级 | 自动 |
| 核心依赖半开探测成功 | 全面降级 → 局部降级 | 自动恢复 |
| 兜底数据也不可用 | 全面降级 → 服务不可用 | 触发人工介入 |
| 人工介入恢复后 | 服务不可用 → 全面降级 | 人工 |
3.2 每一层的降级手段
第一层:API Gateway
sql
体验AI代码助手
代码解读
复制代码
收到请求 → 检查下游错误率:> 50% → 直接返回降级响应(不转发,保护下游) → 检查限流状态: per-tenant QPS 超出 → 返回 429 + Retry-After per-API 全局限流 → 返回 503
第二层:服务内部熔断器(三态机)
| 熔断器状态 | 行为 | 转换条件 |
|---|---|---|
| 关闭态(Closed) | 正常处理,统计错误率 | 错误率 > 50% → 转为开启态 |
| 开启态(Open) | 直接拒绝,返回 fallback | 等待 30s → 转为半开态 |
| 半开态(Half-Open) | 放行 5% 流量探测恢复 | 探测成功 → 关闭态;失败 → 开启态 |
第三层:数据层降级(级联兜底)
ini
体验AI代码助手
代码解读
复制代码
数据库不可用 → 读 Redis 缓存(可能有秒级延迟) → 读本地缓存(可能有分钟级延迟) → 返回静态兜底数据(标记 degraded=true)
3.3 降级响应的标准格式:不能悄悄返回过时数据
json
体验AI代码助手
代码解读
复制代码
{ "data": { "...": "..." }, "meta": { "degraded": true, "degraded_reason": "upstream_redis_timeout", "data_freshness_at": "2026-06-15T10:30:00Z", "data_freshness_lag_seconds": 47, "retry_after_seconds": 30, "user_message": "数据更新中,显示的是约 1 分钟前的版本" } }
原则:降级时用户必须被告知,永远不要悄悄返回可能过时的数据而不作任何标识。 这是系统诚实性的基础。
3.4 架构师如何判断"降级到什么程度"
vbnet
体验AI代码助手
代码解读
复制代码
告警触发 ↓ 【判断】影响的是哪一级链路? → 核心不可降级链路 → 不降级,直接 fail-fast → 触发 On-Call → 考虑切换到备用区域 → 重要可降级链路 → 有缓存/静态兜底数据? 是 → 返回缓存数据 + 标记 degraded + 时间戳 + 继续监控恢复 否 → 关闭该功能入口 + 展示"服务维护中"提示 → 可降级/尽力而为链路 → 静默降级,不影响用户主流程 → 后台记录,异步补偿 ↓ 持续监控:错误率 / P99 / Error Budget 消耗 ↓ 恢复信号稳定 5min → 逐步恢复(先放 5% 流量 → 正常)
四、变更管理:70% 的故障来自变更
4.1 灰度发布的正确姿势
matlab
体验AI代码助手
代码解读
复制代码
发布阶段(每个阶段都有自动门禁): 1% Canary(内部用户/测试租户) 监控 15-30min → 门禁检查通过 ↓ 5% 灰度(低价值租户) 监控 30-60min → 门禁检查通过 ↓ 20% 灰度 监控 1-2h → 门禁检查通过 ↓ 100% 全量 监控 24-48h 每个阶段的自动门禁条件(全部满足才能进入下一阶段): ✓ 错误率变化 < 基线 ± 3σ ✓ P99 延迟无明显上升 ✓ 无新增关键告警 ✓ 核心业务指标稳定 任意阶段异常:一键回滚(K8s 蓝绿切换,< 5min,无需重新部署)
关键原则:发布门禁必须是自动化的,不能靠人工判断。人在发布压力下容易忽视早期异常信号。
4.2 功能开关:解耦发布与上线
功能开关(Feature Flag)让代码发布和功能上线解耦,是降低变更风险的重要手段:
erlang
体验AI代码助手
代码解读
复制代码
步骤 1:开发者提交代码(功能默认关闭) 步骤 2:CI/CD 部署到生产环境(用户看不到新功能) → 此时代码在线,但功能不可见 步骤 3:通过 Feature Flag 系统开启 1% 租户(无需重新部署,实时生效) → 1% 用户可见新功能 步骤 4-A(出现问题): 关闭 Feature Flag → 秒级生效,所有用户看不到新功能 无需任何代码部署,极低风险 步骤 4-B(功能正常): 逐步扩大比例:10% → 50% → 100%
五、混沌工程:主动发现系统薄弱点
5.1 混沌实验的标准流程
erlang
体验AI代码助手
代码解读
复制代码
第 1 步:定义稳态 → 正常情况下的系统指标基线(P99、错误率、QPS) 第 2 步:提出假设 → "当 X 发生时,SLO 不会被违反" → 例:当一个 Pod 随机宕机时,P99 < 300ms 的 SLO 不受影响 第 3 步:设计实验 → 限定爆炸半径(5% 流量 / 指定租户 / 非工作时间) 第 4 步:执行并持续观测 → 监控 SLI 指标,记录基线偏差 第 5 步:评估结果 → SLO 未被违反 → 假设成立,系统对此场景有韧性 → SLO 被违反 → 发现真实薄弱点,创建高优先级修复任务 第 6 步:修复后重新实验 → 验证修复有效
重要约束:只有在 Error Budget 充裕(消耗 < 50%)时才进行混沌实验。Error Budget 已紧张时,混沌实验是在加速耗尽预算。
六、故障复盘:让每次故障产生价值
Postmortem 文档需要在故障恢复后 24-48 小时内完成,包含以下模块:
| 模块 | 内容要求 |
|---|---|
| 影响摘要 | 时间线 + 影响范围 + Error Budget 消耗量 |
| 根本原因 | 5 Why 深挖(不是"谁操作失误",而是"哪个系统设计让失误成为灾难") |
| 时间线重建 | 分钟级,故障发现 → 响应 → 恢复的完整过程 |
| 行动项 | 每项有负责人和 Deadline,必须有 P0 预防措施 |
| 行动项追踪 | 纳入下次 Sprint,防止复发 |
无指责(Blameless)原则:Postmortem 的目标是系统改进,不是追责。如果工程师担心被问责,他们会隐瞒信息,导致根本原因无法找到。
研究小结
稳定性工程的三个层次形成闭环:
markdown
体验AI代码助手
代码解读
复制代码
预防(减少故障发生) SLO 定义 + 变更管理 ↓ 保护(限制故障影响范围) 降级收敛 + 熔断 ↓ 恢复(快速从故障中恢复并学习) 自动恢复 + Postmortem ↓ (持续改进) 回到:预防
架构师在稳定性设计上的核心价值:不是消灭故障,而是设计好每一层的降级路径,使得任何单一故障都只影响有限范围,并能自动恢复到正常状态。
作者:_遥远的救世主_
链接:https://juejin.cn/post/7651183007399706687
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)