首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >混沌演练入门:主动断一次服务看反应

混沌演练入门:主动断一次服务看反应

原创
作者头像
延迟慢慢消解
发布于 2026-10-22 11:47:21
发布于 2026-10-22 11:47:21
200
举报

前年做大促保障,我们按惯例做压测,各项指标都好看。有位同事提了一句:压测只测了「量变大」,没测「东西坏了」。于是在大促前两周的一个晚上十点,我们把订单查询服务的一个下游调用延迟从三十毫秒调到两秒,只影响百分之二十的实例。

八分钟后,下单链路大面积超时。原因不是延迟本身,是连接池的等待队列被打满,线程全部堵在那儿,连带把不相关的接口也拖死了。这个问题压测永远测不出来,因为在压测里下游一直是好的。后来我们把延迟调回去,改了三处配置,大促期间再没出现过同类问题。

这就是混沌演练:不是等故障发生,而是主动制造一个可控的故障,看系统怎么反应。听着吓人,做好边界控制之后,风险比不演练小得多。下面讲怎么入门。

一、先想清楚要验证什么

1.1 没有稳态指标就不要开练

演练之前必须能回答一个问题:系统什么样算正常。这个「正常」要能被量化成几个指标,比如接口成功率不低于九成九、订单积压不超过五百单、核心接口响应时间在八百毫秒以内。

指标定不出来,演练就没有终点。故障注入之后,你只能凭感觉判断「好像还行」,这种判断没有价值,出事的时候也不会有告警告诉你。

1.2 从只读链路开始

头一次演练别碰写链路。查询类接口挂了,用户看到报错,影响面可控;下单、支付这类写接口出问题,可能产生脏数据,事后清理的成本远高于演练收益。

我们的顺序是:先内部管理后台,再查询接口,再非核心写接口。每进一级,观察两周,确认监控和预案都跟得上,再往下走。跳级演练的结果通常是发现问题一大堆,但没有能力处置。

管理后台这类系统特别适合起步,因为使用者是内部员工,出问题打个电话就能说明白,不会引发外部投诉。在这个环境里把中止流程、通知机制、记录模板跑熟,再往真实业务上搬。

1.3 爆炸半径写进配置

爆炸半径说的是这次故障影响多少人、多少机器、多长时间。这个范围不能靠口头约定,必须写在配置里,由执行工具强制执行。

我们的默认设置是:灰度环境不限,预发环境百分之二十实例,生产环境不超过百分之五实例且只在业务低峰执行。单次持续时间不超过三分钟,超时自动恢复。这几条写死在模板里,谁要用生产环境都得改模板,改动会被评审看到。

二、四种基础故障

2.1 延迟注入

在调用链路上加固定或随机延迟,模拟下游变慢。这是入门首选的故障类型,因为它的影响是渐进的,能观察到系统从正常到劣化的完整过程。

延迟注入要配抖动。固定延迟容易被超时重试机制完美绕过,加了抖动之后,重试的节奏被打乱,连接池压力才会真实暴露出来。

2.2 错误注入

让一定比例的请求直接返回错误码,模拟下游不可用或者逻辑异常。这个故障考验的是重试、熔断、降级三套机制是否真的生效。

要注意错误码的选择。返回五百和返回四〇四,上层处理逻辑完全不同,四〇四一般不会触发重试,五百会。注入之前先确认你想验证的是哪条路径。

2.3 实例下线

直接干掉一部分实例,模拟机器故障或者发布过程中的实例重启。这个故障考验的是负载均衡摘除速度和剩余实例的承载能力。

实例下线是破坏性操作,只能在有副本、有自动伸缩的环境里做。单实例服务做这个演练,等于直接停服,那不叫演练,叫事故。

我们头一次做这个演练,掉了两台实例,负载均衡用了将近九十秒才把流量摘干净,这九十秒里有一批请求打到了已经停掉的机器上,用户看到的是连接被拒。后来把健康检查间隔从三十秒改到五秒,同样的演练,影响时间缩到十秒以内。

2.4 依赖超时

把某个依赖的响应时间调到超过调用方的超时阈值,看调用方是快速失败还是死等。这类故障在真实环境里很常见,一个慢查询拖垮整个页面。

依赖超时要和延迟注入区分开:延迟注入是「慢一点」,依赖超时是「慢到必然超时」,前者看劣化曲线,后者看失败处理。

三、把实验写成配置

演练不能靠人手敲命令。手敲的问题是不可复现,昨天怎么做的记不清,出了问题也说不清当时的参数。下面这份 JSON 描述的是一次完整的实验,包含目标、稳态校验、故障定义、中止条件和记录方式。

代码语言:json
复制
{
  "experiment": "order-query-degrade",
  "version": 1,
  "target": {
    "service": "order-query",
    "scope": "cluster",
    "percent": 20,
    "labels": { "env": "staging" }
  },
  "steady_state": {
    "window_seconds": 300,
    "checks": [
      { "metric": "api_success_rate", "op": ">=", "value": 0.995 },
      { "metric": "p99_latency_ms", "op": "<=", "value": 800 },
      { "metric": "pending_orders", "op": "<=", "value": 500 }
    ]
  },
  "faults": [
    { "type": "latency", "delay_ms": 1200, "jitter_ms": 200, "duration_seconds": 180, "percent": 20 },
    { "type": "error", "code": 503, "rate": 0.1, "duration_seconds": 180, "percent": 20 }
  ],
  "abort": {
    "on_steady_state_violation": true,
    "consecutive_breaches": 3,
    "cooldown_seconds": 60,
    "auto_recover": true
  },
  "notify": {
    "channel": "ops-alert",
    "before_start_minutes": 10,
    "on_abort": true,
    "on_finish": true
  },
  "record": {
    "save_trace": true,
    "tag": "chaos-order-query-r1"
  }
}

3.1 结构拆解

target 定义打谁、打多少、打哪个环境。steady_state 定义什么算正常,里面的三个指标是自动中止的判断依据。faults 是一个数组,可以一次注入多种故障,也可以分阶段执行。

abort 是整份配置里要紧的一段。连续三次稳态校验不通过就自动中止,中止后冷却一分钟再恢复,避免故障刚撤掉就被流量冲垮。没有这段配置的演练,我不建议在生产环境做。

3.2 稳态校验与自动中止

稳态校验的逻辑是:演练开始前先观察五分钟,确认指标在阈值内;注入过程中每三十秒采一次,连续三次越界就中止。这个「连续」很关键,单次抖动不中止,否则一有毛刺就停,演练跑不完。

阈值怎么定?按历史正常波动定。拿过去两周同一时段的指标分布,取分位数,别直接拍一个整数。定得太紧,天天误中止;定得太松,出事了也不停。

3.3 执行顺序与灰度

一次实验里多个故障不要同时开。先延迟,观察两分钟,再叠错误注入,这样能看出是哪一种故障触发了劣化。同时开的话,只能知道「坏了」,不知道「为什么坏」。

执行范围按百分之五、百分之二十、百分之五十三档递进。每一档跑完看结果,没问题再放大。这套流程听着慢,但一次跑通之后,后续实验可以直接复用模板。

这套调度我们放在搭贝的定时任务里,到点自动开跑,结束后自动撤掉故障开关。

四、演练当天怎么跑

4.1 谁按开关

必须有一个人专门负责中止,这个人不参与排查,只盯着稳态指标和中止按钮。让排查的人同时管中止,出问题时他一定先去看日志,不会记得按按钮。

还要有一个对外沟通的人。演练期间如果客服、业务方来问,由他统一回复,避免一线以为真出故障,触发不必要的升级流程。

4.2 盯哪几个数

盯三类:入口的成功率和延迟、关键业务的积压量、依赖的错误率。入口指标反映用户感受,积压量反映业务影响,依赖错误率用来定位原因。

别盯机器指标。CPU 打到八十不代表有问题,CPU 只有二十也可能因为等锁而全线卡住。机器指标是辅助,业务指标才是判断依据。

4.3 复盘产出

演练结束当天出一份记录:注入了什么、系统怎么反应、哪一层先撑不住、预案有没有生效、需要改什么。记录里要有时间线,精确到分钟,事后才能对上日志。

需要改的项要落成工单,写清负责人和期限。没有工单的复盘等于没做,下次演练还会遇到同一个问题。我们头一年做了六次演练,改出来的东西包括连接池上限、超时阈值、熔断窗口,都是压测发现不了的。

常见问题

问:小团队没有专职运维,能做混沌演练吗?

答:能,从灰度环境开始。不需要复杂工具,写个脚本定时给某个接口加延迟,观察十分钟,也是演练。关键是先把稳态指标定出来,哪怕只有两个指标,也比没有强。等这套流程跑顺了,再考虑引入自动化平台。

问:演练把生产环境搞挂了,责任算谁的?

答:算流程的。如果中止条件写清楚、爆炸半径控制在约定范围内,演练期间的短时劣化属于预期成本,不该追个人责任。反过来,如果没写中止条件、超范围操作,那是流程缺失,要补的是流程,不是罚人。

问:每次都自动中止,是不是阈值定得太严?

答:先看中止时的指标是不是真的越界。如果只是轻微越界,说明阈值贴着正常波动,要放宽;如果确实明显劣化,那是系统真的扛不住,该改系统而不是改阈值。别为了让演练跑完而放松阈值,那是自欺欺人。

问:演练频率多久一次合适?

答:按变更频率定。每季度有大版本发布的,每季度一次;天天发版的,可以每周小范围跑一次。频率太高会消耗团队精力,太低又起不到作用。我们的做法是核心链路每季度一次全流程,日常每周一次单点故障,两种节奏并行。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 一、先想清楚要验证什么
    • 1.1 没有稳态指标就不要开练
    • 1.2 从只读链路开始
    • 1.3 爆炸半径写进配置
  • 二、四种基础故障
    • 2.1 延迟注入
    • 2.2 错误注入
    • 2.3 实例下线
    • 2.4 依赖超时
  • 三、把实验写成配置
    • 3.1 结构拆解
    • 3.2 稳态校验与自动中止
    • 3.3 执行顺序与灰度
  • 四、演练当天怎么跑
    • 4.1 谁按开关
    • 4.2 盯哪几个数
    • 4.3 复盘产出
  • 常见问题
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档