3072 字
约 10 分钟
17
S17-A10 · 故障演练的范围:投入多少才值

演练做了一次,真出事还是手忙脚乱——这是"只做过一次演练"的团队的标准结局。原因不在演练本身,在目标定错了:多数演练在验证"系统能不能扛住",而真出事时决定后果的是人能不能在信息不全时做出正确判断、流程能不能在压力下跑通。系统扛不扛是压测与容量规划的事;演练唯一不可替代的价值,是把人和流程放进真实故障的时序里跑一遍。本文只谈投入决策:多大爆炸半径、多高频率、什么条件下根本不该演练。


1. 演练要回答的问题

问题 谁能回答 演练是否必要
单机能扛多少 QPS 压测 不需要
依赖挂掉后降级是否生效 单点注入 需要
值班能否 5 分钟内定位到正确服务 桌面推演 + 告警链路 需要
主库不可用时切换要多久 链路故障 需要,风险最高
全站不可用时对外沟通谁负责 桌面推演 需要,成本最低

判据:能被压测回答的问题不要用演练回答。演练的成本是"真实影响用户",压测的成本是"占用测试环境",不在一个量级。用演练验证容量,是最贵的错误用法。


2. 四种强度:成本跃升来自组织,不来自技术

强度 做法 参与人 成本 风险
桌面推演 念剧本,问"下一步做什么" 5–10 人,2 小时 极低 无
单点注入 杀实例、断连接 1–2 人 + 值班 低 低
链路故障 停依赖、注入延迟/错误率 团队级,需预案 中 中
全站演练 多故障叠加、跨团队 组织级,需公告 高 高

从单点到链路的成本跃升,原因不是技术复杂度,而是需要跨团队预案:单点失败回滚即可,链路故障失败需要有人判断"降级还是回滚",而这个人往往没被授权。务实路径是桌面推演 → 单点注入 → 链路故障,每一步的缺口清单关闭后才升级。


3. 先有可观测,再有演练

看不见故障的演练不是演练,是制造事故。判据只有一句:注入一个已知故障,告警是否在预期时间内到达值班? 答案是否,当前该补监控。

能力 缺失时的表现 演练会变成什么
指标与看板 注入后没人发现异常 白做,消耗团队信任
告警链路 异常发生但没通知到人 变成"发现告警没配"
日志检索 定位靠猜 排障时间被算进演练耗时
链路追踪 不知道坏在哪一跳 结论只能写"某处有问题"

演练的价值来自"验证人对信号的响应",信号缺失时它只剩破坏。


4. 三个前置条件

条件 要求 不满足的后果
回滚可行 注入可控、有开关、能一键恢复 演练故障变真实故障
影响可控 半径明确、有灰度、有时间窗 波及真实用户且无法止损
值班在位 有人在岗且知道这是演练 没人处理,或处理者不知情

最容易忽略的是第三条:"值班在位"不等于"有人在线",而是"知道这是一次演练、知道怎么终止"。曾出现演练注入后被不知情工程师当真实故障扩容、把影响放大的案例——这是知情范围问题,不是技术问题。

# 演练前先验证回滚脚本能跑通,再谈注入
./chaos rollback-check --experiment "$EXP_ID" --timeout 60 \
  && echo "rollback ok" || { echo "abort: rollback broken"; exit 1; }

5. 注入点与可恢复性

注入点 手段 可恢复性 风险
网络 延迟、丢包、分区(tc/iptables) 高,撤销即恢复 中,易误伤
进程 杀实例、暂停(kill/stop) 高 低(有冗余时)
依赖 错误率、超时、异常返回 中,需确认降级 中
资源 占满 CPU/内存/磁盘/连接数 低,恢复慢且易残留 高
数据 删改记录、制造不一致 极低,可能不可逆 最高

判据:数据层注入只在数据可重建的环境做。生产库的数据注入恢复依赖备份,RTO 通常是小时级,那是事故预演不是演练。资源类要注意"恢复残留":进程被杀后页缓存与交换的影响会持续一段时间,指标恢复不等于系统恢复。


6. 爆炸半径:四道闸缺一不可

experiment:
  target: { service: checkout, selector: "zone=b", percent: 5 }   # 单可用区 + 小比例
  blast_radius:
    max_affected_requests_per_min: 50
    abort_if_error_rate_over: 0.02        # 越线立即自动终止
    abort_if_latency_p99_over_ms: 800
  window: { start: "02:00", end: "03:00" }  # 低峰 + 硬截止
  rollback: { command: "./chaos stop --id $EXP_ID", timeout_s: 60 }

范围、自动止损、时间窗、回滚脚本。自动止损比人工判断重要,因为异常往往先被用户发现;止损条件必须在注入前写死。


7. 与故障响应的联动

演练最有价值的产出常常不是"发现架构缺陷",而是"发现告警发给了错的人"。

# 打标而不是静默:静默会让"告警是否触发"变得不可观测
curl -s -XPOST "$ALERT_API/labels" \
  -d '{"match":"env=prod","set":{"chaos":"true","exp":"EXP-042"}}'
curl -s -XPOST "$ALERT_API/notify" \
  -d '{"channel":"oncall","text":"02:00-03:00 演练中,告警请人肉响应"}'
联动项 要验证的 常见缺口
告警触发 阈值与聚合是否生效 依赖指标没上报
发给谁 值班表是否正确 值班表半年没更新
升级路径 一级不响应后是否升级 升级链断在某人

不要用静默掩盖演练,那会让最关键的问题变成不可观测。正确做法是打标签并在通知里明示。


8. 产出物与"通过"的误读

产出 内容 后续
缺口清单 现象、根因、影响、建议 进排期,指定 owner 与期限
时间线 注入到恢复的每个动作时刻 算 MTTD/MTTR
决策记录 为何选降级而非回滚 补进 runbook

“完全按计划完成”的演练,几乎必然强度不足。好的演练至少暴露一条预期外现象;什么都没暴露,先怀疑注入无效而不是庆祝健壮。

# 验证注入确实生效:60 秒内指标无可观测变化就中止
sleep 60
rate=$(curl -s "$PROM/api/v1/query" --data-urlencode \
  "query=sum(rate(http_requests_total{service=\"checkout\",code=~\"5..\"}[1m]))" | jq -r '.data.result[0].value[1] // 0')
[ "$(echo "$rate > 0" | bc)" -eq 1 ] || { echo "injection ineffective"; ./chaos stop --id "$EXP_ID"; }

9. 频率跟随变更,不跟随日历

变更频率 建议频率 理由
每周多次发布 每月单点 + 每季链路 变更多,故障面变化快
每月数次 每季一次 与变更窗口对齐
季度级发布 半年一次,桌面推演为主 形态稳定,回报低
架构大改前后 各一次,必做 变更本身是最大风险源

新增强依赖、换数据库、改部署拓扑,都比"又过了一年"更值得触发一次演练。


10. 生产与预发的分工

维度 预发演练 生产演练
验证对象 降级逻辑、配置正确性 告警链路、人的响应、真实流量
风险 低 高
常见误用 把预发通过当成生产可用 用生产演练验证代码逻辑

预发验证"代码是否按设计动作",生产验证"人和流程是否动作"。前者失败是缺陷,后者失败是组织问题。用生产演练发现代码 bug,是把最贵的环境用在最便宜的问题上。


11. 文化障碍与制度解法

怕背锅、怕影响业务、怕暴露问题、怕麻烦、走过场——解法都是制度而非号召。核心是把"发现缺口"从负面事件变成正面产出:缺口由平台团队统一收集,考核修复率而非缺口数量;演练窗口进季度计划并提前公告。缺口清单一旦导致问责,下一季度演练就只剩表演。


12. 度量:只看两个数

-- MTTD/MTTR 按演练与真实故障分开统计,避免互相污染
SELECT kind,
       percentile_cont(0.5) WITHIN GROUP (ORDER BY detected_at - injected_at) AS mttd,
       percentile_cont(0.5) WITHIN GROUP (ORDER BY recovered_at - detected_at) AS mttr,
       count(*) FILTER (WHERE gap_closed)::float / count(*) AS gap_close_rate
FROM incidents
WHERE created_at > now() - interval '180 days'
GROUP BY kind;
指标 健康信号
MTTD 逐季下降,且演练值与真实值差距缩小
MTTR 不追求极小,追求可预测
缺口关闭率 上升;长期低于一半说明治理失效

不要用"演练次数"当指标,它只会催生走过场。MTTD 的演练值与真实值接近,才是演练真正有效的证据——说明告警链路在两种情况下表现一致。


13. 排错:演练做完了但没价值

现象 根因 处理
注入后指标毫无变化 注入未生效或打到无流量实例 先验证生效再走流程
演练中无人响应 告警未配或值班表过期 补规则,更新值班表
缺口清单没人修 无 owner、无期限 进排期,设回归验证
复盘变成追责 无时间线,只能靠记忆 强制记录时间线
演练影响真实用户 无自动止损、时间窗错 加止损与低峰窗口
每次演练都成功 剧本过细、强度不足 引入未知变量与叠加故障

14. 边界:这些阶段先别演练

场景 该做什么
系统刚上线 先补监控与回滚,桌面推演即可
无监控/无告警 补可观测,演练无意义
团队不足三人 桌面推演 + runbook,不做注入
单点故障不影响业务 记录为已知风险,不值得投入
无冗余的单实例 注入等于制造故障,先做冗余
强合规/不可中断业务 只在预发演练,生产做只读验证

最终口径:演练价值 = 缺口修复价值 − 演练影响 − 协调成本。任一项估不出来,说明还没到该演练的阶段。


15. 自测

  1. 为什么"系统能不能扛住"不该由演练回答?
  2. 从单点注入升级到链路故障,成本跃升的真实原因是什么?
  3. 注入一个已知故障后告警没响,下一步该做什么?
  4. 为什么不能用静默(silence)掩盖演练?
  5. 一次"完全按计划完成"的演练,应该怀疑什么?
  6. MTTD 的演练值与真实值接近,说明什么?
S17-A10 · 故障演练的范围:投入多少才值
https://www.clxhxhhr.top/posts/6219/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。