别再写“演练方案”了:真正靠谱的 Incident Playbook,应该能直接跑起来

举报
Echo_Wish 发表于 2026/09/14 08:34:03 2026/09/14
【摘要】 别再写“演练方案”了:真正靠谱的 Incident Playbook,应该能直接跑起来

别再写“演练方案”了:真正靠谱的 Incident Playbook,应该能直接跑起来

凌晨 2 点,告警突然炸了。

CPU 100%,接口大量 5xx,订单开始超时。

值班同学打开群聊:

“先看看是不是数据库问题。”

“我这边看应用日志没发现异常。”

“要不要先重启一下?”

“谁有之前那个故障处理文档?”

“等一下,我找找……”

五分钟过去了。

十分钟过去了。

最后大家发现:真正的问题不是没人知道怎么处理,而是知道的东西根本没有变成可以执行的东西。

这也是我越来越强烈的一个感受:

Incident Playbook 如果只能拿来“阅读”,那它其实还没有真正完成。

真正成熟的 Playbook,不应该是一篇写得很漂亮的 Word 文档,而应该更像一套“故障处理程序”。

甚至可以进一步:

把故障演练写成代码,让 Playbook 本身具备可执行、可验证、可回归测试的能力。

这才是 Incident Playbook 可测试化真正有意思的地方。


一、为什么很多故障演练,最后都变成了“开会演戏”?

传统的故障演练,大概是这么玩的。

提前准备一份方案:

场景:数据库连接池耗尽
现象:接口大量超时
处理步骤:

  1. 查看数据库连接数
  2. 检查应用连接池
  3. 查看慢 SQL
  4. 必要时重启应用
  5. 恢复业务

看起来没毛病。

然后演练开始。

负责人说:

“现在模拟数据库连接池耗尽。”

A 同学:

“我会先查看监控。”

B 同学:

“然后检查应用日志。”

C 同学:

“如果确认连接池满了,我会进行扩容。”

大家点点头。

演练结束。

总结:

“本次演练圆满完成。”

但是问题来了:

你真的验证了吗?

你有没有验证:

  • 告警到底会不会触发?
  • 告警触发后多久能发现?
  • 值班人员能不能拿到正确信息?
  • Playbook 里面的命令还能不能执行?
  • 权限还存在吗?
  • 依赖的接口还存在吗?
  • 自动恢复真的有效吗?
  • 回滚真的能够成功吗?
  • 业务指标恢复了吗?

如果这些都没有验证,那么这更像是:

大家一起把剧本念了一遍。

而不是一次真正的故障演练。


二、Playbook 最大的问题:写的是“人话”,执行需要的是“机器话”

我们来看一个非常典型的 Playbook。

发现 API 5xx 增加
        ↓
检查应用状态
        ↓
检查数据库
        ↓
确认是否为数据库连接问题
        ↓
如果连接池耗尽,则重启应用
        ↓
观察错误率
        ↓
恢复正常后结束

人当然能看懂。

但机器看不懂。

因为里面大量都是模糊描述:

“检查应用状态。”

到底检查什么?

“观察错误率。”

多少算恢复?

“如果连接池耗尽。”

多少算耗尽?

所以我认为:

Playbook 可测试化的第一步,不是写代码,而是把模糊的人话变成明确的判断条件。

例如:

incident:
  name: api_database_connection_exhaustion

trigger:
  metric: http_5xx_rate
  condition: "> 5%"
  duration: "3m"

diagnosis:
  db_connection_usage:
    condition: "> 90%"

remediation:
  action: restart_application

success:
  http_5xx_rate: "< 1%"
  duration: "5m"

这时候事情就完全不一样了。

因为它已经不再是一篇“建议怎么处理”的文档。

它开始变成:

一份机器可以理解的故障契约。


三、真正的 Playbook,应该像测试用例一样写

如果让我重新设计 Incident Playbook,我会把它拆成几个非常明确的部分:

Trigger
↓
Detect
↓
Diagnose
↓
Remediate
↓
Validate
↓
Rollback

其实和我们写测试代码特别像。

比如一个“Redis 故障”的演练:

def test_redis_failure_recovery():

    inject_redis_failure()

    assert wait_for_alert("RedisUnavailable")

    assert api_error_rate() > 0.05

    run_playbook("redis-failure")

    assert wait_until(
        lambda: api_error_rate() < 0.01,
        timeout=300
    )

    assert redis_connection_count() < 1000

注意这里最关键的不是 Python。

而是最后一句:

assert

没有 assert 的演练,很容易变成表演。

因为你必须明确告诉系统:

什么叫成功?


四、故障演练最应该测试的,其实不是“你会不会处理”

很多团队做演练的时候,非常关注一个问题:

“这个工程师会不会处理故障?”

但成熟的工程体系,更应该关注:

“我们的系统到底有没有能力让一个普通值班人员正确处理故障?”

这是完全不同的思路。

假设 Playbook 写着:

kubectl rollout restart deployment/order-service

看起来非常简单。

但是到了真正的生产环境:

error: deployments.apps "order-service" not found

为什么?

因为三个月前服务已经改成:

order-api

Playbook 没更新。

这种事情特别常见。

所以 Playbook 本身也应该进行自动化测试。

例如:

def test_playbook_command():

    result = run_command(
        "kubectl get deployment order-service"
    )

    assert result.exit_code == 0

如果失败:

❌ Playbook validation failed

Service: order-service
Command: kubectl get deployment order-service
Reason: resource not found

这时候你甚至不用等故障发生。

Playbook 已经提前告诉你:这份剧本过期了。


五、把 Playbook 当成代码管理,而不是 Word 文档

这是我特别推荐的一种方式。

不要:

故障处理手册.docx

而是:

incident-playbooks/
├── api/
│   ├── high-5xx.yaml
│   ├── high-latency.yaml
│   └── service-down.yaml
│
├── database/
│   ├── connection-exhaustion.yaml
│   ├── slow-query.yaml
│   └── primary-failure.yaml
│
├── cache/
│   ├── redis-down.yaml
│   └── redis-memory-high.yaml
│
└── tests/
    ├── test_api.py
    ├── test_database.py
    └── test_cache.py

然后直接进入 Git。

这样你就拥有了很多传统文档没有的能力:

Git
 ↓
Code Review
 ↓
CI
 ↓
Playbook Test
 ↓
发布

以后修改生产架构的时候:

修改服务
   ↓
修改 Playbook
   ↓
修改测试
   ↓
CI 自动验证
   ↓
全部通过

这时候 Playbook 才真正成为了生产系统的一部分。


六、甚至可以给 Playbook 写 CI

这个思路其实非常有意思。

假设我们规定:

所有 P1/P2 级故障 Playbook,必须通过自动化测试才能合并。

那么 CI 可以这样跑:

name: Incident Playbook Test

on:
  pull_request:

jobs:
  playbook-test:

    runs-on: ubuntu-latest

    steps:

      - name: Checkout
        uses: actions/checkout@v4

      - name: Validate YAML
        run: python scripts/validate_playbook.py

      - name: Run Playbook Tests
        run: pytest tests/

      - name: Check Commands
        run: python scripts/check_commands.py

      - name: Check Rollback
        run: python scripts/test_rollback.py

于是以后有人修改:

remediation:
  action: restart_application

CI 就会告诉你:

❌ Rollback test failed
❌ Validation condition missing
❌ Command not executable

这就很舒服了。

因为以前是:

出事故 → 发现 Playbook 不能用。

现在变成:

提交代码 → 就发现 Playbook 不能用。

故障还没发生,问题已经被发现了。


七、真正高级的玩法:故障注入 + Playbook 自动执行

如果只是验证 Playbook 文件格式,其实还不够。

更进一步,可以把它和故障注入结合起来。

比如我们有一个订单服务:

order-api
    ↓
Redis
    ↓
MySQL
    ↓
MQ

现在模拟 Redis 故障:

def chaos_test():

    # 1. 注入故障
    chaos.kill("redis")

    # 2. 验证告警
    assert alert("RedisUnavailable")

    # 3. 自动执行 Playbook
    execute_playbook(
        "redis-failure"
    )

    # 4. 验证业务
    assert wait_until(
        lambda: order_success_rate() > 0.99,
        timeout=300
    )

    # 5. 验证故障清理
    assert chaos.active_faults() == []

这时候整个过程已经形成闭环:

制造故障
   ↓
触发监控
   ↓
产生告警
   ↓
执行 Playbook
   ↓
恢复服务
   ↓
验证业务
   ↓
清理故障

这已经不是传统意义上的“演练”了。

这其实就是:

Incident Playbook 的自动化回归测试。


八、别只验证“服务活了”,一定要验证“业务活了”

这里还有一个非常容易踩坑的地方。

比如:

assert http_status() == 200

测试通过。

但是用户还是无法下单。

为什么?

因为:

HTTP 200
≠
业务正常

所以真正的故障恢复测试,最好分成三层。

第一层:基础设施

assert pod_status() == "Running"
assert cpu_usage() < 80
assert memory_usage() < 80

第二层:应用

assert api_error_rate() < 0.01
assert api_latency_p99() < 500

第三层:业务

assert order_success_rate() > 0.99
assert payment_success_rate() > 0.99

最终判断应该是:

机器活了
+
服务活了
+
业务活了
=
真正恢复

而不是:

Pod Running
=
事故结束

九、Playbook 还应该测试“权限”

这个问题特别容易被忽略。

很多 Playbook 在写的时候:

kubectl delete pod xxx

作者自己执行当然没问题。

但是半年以后,真正值班的人执行:

Error: Forbidden

因为 RBAC 权限已经调整。

所以可以增加:

def test_operator_permission():

    result = run_as(
        role="oncall",
        command="kubectl get pods"
    )

    assert result.exit_code == 0

甚至可以进一步检查:

assert can_execute(
    role="oncall",
    command="restart deployment"
)

assert not can_execute(
    role="oncall",
    command="delete production database"
)

这就把一个非常现实的问题解决了:

Playbook 写得对,不代表值班人员执行得了。


十、还要测试“时间”,因为事故不是做题

生产事故和考试最大的区别是什么?

考试没有用户流失,事故有。

所以 Incident Playbook 不应该只关心:

最终能不能恢复?

还应该关心:

多久能发现?

多久能定位?

多久能执行?

多久能恢复?

例如:

assert detection_time < 60
assert diagnosis_time < 300
assert remediation_time < 600
assert recovery_time < 900

这时候你就可以得到:

MTTD = 42s
MTTI = 183s
MTTR = 527s

然后每次演练都做对比:

第一次:MTTR 18min
第二次:MTTR 11min
第三次:MTTR 7min

这才叫真正的工程改进。

否则每次复盘都是:

“以后加强监控。”

这种话说十遍,系统也不会自动变好。


十一、我特别喜欢一个思路:让 Playbook 自己证明自己没过期

现实里最大的 Playbook 问题之一,就是:

它会腐烂。

服务变了。

架构变了。

命令变了。

权限变了。

监控指标变了。

但是文档还停留在两年前。

所以可以定期执行:

def validate_all_playbooks():

    for playbook in load_playbooks():

        assert syntax_valid(playbook)

        assert dependencies_exist(playbook)

        assert commands_available(playbook)

        assert permissions_valid(playbook)

        assert rollback_defined(playbook)

        assert success_condition_defined(playbook)

最终生成:

Incident Playbook Health Report

Total: 86

Passed: 79
Warning: 5
Failed: 2

❌ mysql-primary-failure
   rollback command unavailable

❌ order-api-high-5xx
   alert rule not found

这时候运维团队甚至可以给 Playbook 建一个“健康度”。

比如:

Playbook Health Score

Syntax             100%
Command            96%
Permission         98%
Alert              91%
Rollback           87%
Recovery Test      93%

Overall             94%

故障处理手册,终于也开始有“可观测性”了。


十二、最终你会发现:Playbook 和代码,其实越来越像

传统运维:

文档
 ↓
人执行
 ↓
出了问题再修改文档

成熟运维:

Playbook
 ↓
自动测试
 ↓
CI
 ↓
定期演练
 ↓
生产事故
 ↓
反馈
 ↓
更新 Playbook
 ↓
再次测试

这其实就是软件工程里的:

代码 → 测试 → CI → 发布 → 反馈 → 重构

只不过以前大家把这个方法用在业务代码上,却没有用在事故响应上。

我认为这恰恰是未来 Incident Management 很值得继续发展的一个方向:

Incident Playbook 不应该只是“告诉人怎么做”,而应该能够证明“自己还能不能这么做”。


最后:别把演练当成一次活动,把它当成一次测试

我现在越来越不喜欢“年度故障演练”这种说法。

因为很容易让人产生一种错觉:

一年做一次,拍个照,写个总结,这事就结束了。

但真正靠谱的演练,应该是持续发生的。

今天测试:

Redis 故障

明天测试:

MySQL 主库故障

后天测试:

MQ 堆积

再测试:

API 5xx

甚至可以直接在 CI/CD、预生产环境、混沌工程平台里持续跑。

最终形成这样一套体系:

              Incident Playbook
                     │
          ┌──────────┴──────────┐
          ↓                     ↓
      人工执行                自动执行
          │                     │
          ↓                     ↓
       Drill                  Test
          │                     │
          └──────────┬──────────┘
                     ↓
                  Metrics
                     ↓
               MTTR / MTTD
                     ↓
                  Review
                     ↓
               Playbook Update
                     ↓
                    CI
                     ↓
               Regression Test

这才是我理解的 Incident Playbook 可测试化。

说到底,运维真正害怕的,从来不是“没有文档”。

而是:

事故来了,大家手里都有文档,却没人敢确定这份文档现在到底还能不能用。

所以,与其每年花一天时间“演一场事故”,不如把事故演练变成可以随时运行的测试。

因为真正优秀的运维体系,不是保证:

“我们永远不会出事故。”

而是保证:

“事故真的来了,我们知道怎么发现、怎么处理,而且这套方法已经被反复证明过。”

这两句话,差别很大。

也是运维从“靠经验救火”,走向“靠工程体系抗事故”的一个重要分水岭。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。