2. 混沌工程核心原则:稳态、半径与安

聊完混沌工程是什么,咱们得钻进它的骨架里看看。

说白了,混沌工程不是让你在线上乱搞。它有一套自己的底层逻辑。

你可以把这三个原则当成演练的「交通规则」。不懂规则就上路,迟早翻车。

核心三原则:

  • 稳态假设 — 你得知道「正常」长什么样。
  • 爆炸半径 — 搞事情之前,先划好安全区。
  • 最小化影响 — 能死一只鸡,别杀一头牛。
混沌工程三大核心原则逻辑关系 混沌工程核心原则 稳态假设 定义系统“健康”的基线 爆炸半径 控制故障的影响范围 最小化影响 渐进式、可观测、可中止 可信任的、持续验证的系统韧性

2.1 稳态假设 — 给系统画一幅「健康画像」

你想想看,如果你连系统「正常」的样子都说不清楚,那怎么判断故障演练是有效还是无效?

稳态假设就是这个道理。它指的是:系统在稳定运行时,有一组可观测、可量化的指标。这些指标构成了你对「健康」的定义。

我个人习惯的做法:

每次做演练前,我会提前一周记录黄金指标。比如:

  • 95% 分位响应延迟 < 200ms
  • 每分钟错误数 < 5
  • CPU 使用率波动不超过 20%

把这些写成断言。演练只观测这些指标是否偏离。

我在项目中遇到过一种情况。当时负责一个支付核心系统,团队直接把「接口返回 HTTP 200」当成稳态。结果演练杀了一个依赖服务,接口确实返回 200,但里面塞满了兜底 mock 数据。你想想,这不就是典型的「仪表盘正常,船已经沉了」吗?

所以,好的稳态假设要满足三点:

  • 可观测 — 能从监控、日志、链路追踪里拉出来。
  • 可量化 — 不能是「响应快」,得是「P99延迟 < 500ms」。
  • 有业务含义 — 不只是技术指标,比如「每分钟完成支付的订单数」。

避坑指南:

我曾经在选稳态指标时,只盯着 CPU 和内存看。结果演练把数据库连接池打满了,CPU 没怎么跳,但大量请求在排队超时。从那以后,我要求稳态指标里必须包含业务流量入口的吞吐量。

2.2 爆炸半径 — 炸也要炸得「可控」

爆炸半径,就是一次故障演练「最多只能伤到多大范围」。

说白了,你不能因为想测试一个缓存节点,就把整个集群搞崩了。那就不是演练,是事故。

控制爆炸半径的常用手段:

方法说明我见过的问题
环境隔离先用预发/灰度环境验证,再放大到生产预发环境和生产流量模型差太多,测不出真实问题
用户隔离只影响内部测试账号或特定白名单用户全量用户不可控,容易误伤
实例限制比如只杀掉 1 个 Pod,而不是整个 Deployment一开始就搞大比例,直接雪崩
熔断开关一旦指标越线,自动终止演练开关没联调,演练时手动关都来不及

我记得有一次,团队想验证限流组件的有效性。有人直接提议「把流量网关全部挂掉看看」。我说等等,这么做爆炸半径太大了。最后我们只关了 10% 的网关实例,并观察了 5 分钟。效果很好,找到了一个限流配置的 bug,而且业务方完全没感知。

我自己的原则:

爆炸半径从「最小」开始。先杀一个实例,观测 2-3 分钟。没问题,再杀 10%、20%。别一上来就搞 50% 以上。安全第一,演练第二。

2.3 最小化影响 — 温柔地捅刀子

最小化影响,不是指「不产生影响」,而是指「用最小的代价获取最大的学习价值」。

你想想看,如果可以花 10 秒钟模拟一次 CPU 抖动就能验证限流策略,就没必要花 10 分钟去跑一个全链路压测。

实现最小化影响的两条路:

2.3.1 渐进式演练

从一个低压力、低覆盖率的点开始,逐步扩大。这有点像外科手术,先开个小口,确认方向对了,再扩大切口。

  • 第 1 步:单机、单进程。
  • 第 2 步:多机、单可用区。
  • 第 3 步:多区、非核心业务。
  • 第 4 步:核心业务,但有熔断底线。

2.3.2 自动化中止条件

演练不是无限期的。你必须明确「什么时候该停」。我和团队每次演练前,都会在平台上配置一个「中止阀门」。

// 假代码:中止条件配置示例
stop_conditions:
  - metric: "error_rate"
    threshold: 0.01   # 错误率超过 1% 立刻停止
    duration: "10s"   # 持续 10 秒触发
  - metric: "p99_latency"
    threshold: 1000   # P99 延迟超过 1000ms 停止
    duration: "30s"
  - metric: "success_rate"
    threshold: 0.95   # 成功率跌到 95% 以下停止
    action: "abort"

我曾经在一次演练里,就因为自动中止条件没配好,导致一个关键服务熔断了 20 分钟。虽然最后系统自动恢复了,但影响了大约 2% 的活跃用户。嗯,从那以后,我每次演练前都会亲自检查这三个条件:错误率、P99 延迟、成功率。

一个省钱省力的技巧:

如果你用的是 Kubernetes,可以利用 Pod 的 livenessProbe 和 readinessProbe 来控制演练的影响范围。比如注入故障后,让 Pod 从 Service Endpoint 中摘除,用户流量就不会打到这台有问题的机器上。这算是最低成本的爆炸半径控制之一。

2.4 三个原则的关系

这三个原则不是孤立的。它们是递进关系:

  1. 先定义稳态 — 你才知道系统现在是不是「健康」。
  2. 再控制爆炸半径 — 你才能在不失控的前提下做实验。
  3. 最后追求最小化影响 — 你才能在真实生产环境中重复演练,而不是搞一次就跑路。

说白了,没有稳态假设,你分不清故障是被触发的还是本来就有的。没有爆炸半径,你不敢在生产环境动手。没有最小化影响,你根本得不到持续演练的许可。

一句话总结本章:

混沌工程的高明之处,不在于「敢搞破坏」,而在于「在明确的假设、可控的范围内,用最小的代价搞清楚系统的薄弱点」。