专业书籍精读 · Chaos Engineering · 第 17 章
Chaos Engineering: System Resiliency in Practice · Ch 17 · Let's Get Cyber-Physical · 2020
前面的章节里,「故意搞点故障」的对象是网站和手机应用:最坏情况是一小撮人刷不出视频。可今天软件也在开车、开飞机、控制工厂机械臂和医疗设备。当一次故障可能伤到人,故意制造故障这件事还能不能做、该怎么做?这一章就讲这个。
造汽车、造飞机的工程师,其实比互联网公司早几十年就在「专门研究东西会怎么坏」。他们有一套老办法:开会坐下来,把每个零件挨个点名,问「它会怎么坏?坏了会怎样?有多严重?」,写成一张大表格。这一章的作者说:这套老办法和混沌工程是一对天生的搭档,只是彼此没怎么认识。
老办法负责「把可能的坏法想周全」,新办法负责「证明你的应对真的管用」,结果再写回表格,表格就成了一份会随系统更新的活文档。一句诚实的代价:模拟器再逼真也不是真实世界,越往真实环境靠,试一次就越贵、越要层层把关。
想象出来的故障,要用实验去证实;会伤人的系统,实验先进模拟器和练习场。
想看 FMEA 怎么算风险、为什么软件故障没法估概率、实验该放在仿真 / 台架 / 场地哪一级,以及探针效应怎么对付? → 切到精读版
你以为混沌工程是互联网公司发明的新东西,其实安全关键行业几十年前就在系统性地「想象故障」。本章主张两者互补:功能安全的 FMEA 负责在纸上把故障想周全,混沌工程负责用实验证实这些想象;而在会伤人的物理世界里,实验要先进仿真与台架,并正视「观察本身会改变系统」的探针效应。
全书第 17 章,Part V「演进」,作者 Nathan Aschbacher。上接 Ch16 持续验证——那是混沌工程在 Web 世界的终点形态;这一章把它往外推到软件控制物理设备的领域,下启 Ch18 用「人与组织绩效」视角重看实验设计。
一辆现代汽车上常有上百个电子控制单元(ECU)、代码量常被引用为上亿行的量级;一架无人机的飞控每秒要做数百次姿态解算。软件正在接管原本由机械和人完成的控制,而它出错的后果单位不再是「失败请求的百分比」,而是伤亡。
这些行业早有一套成熟做法——功能安全,由 IEC 61508(通用)、ISO 26262(汽车)、DO-178C(航空软件)等标准约束,核心是设计前先做危害分析、分析做到位再动手。问题在于:
本章要回答的是:混沌工程能给功能安全带来什么,功能安全又会怎样约束混沌工程。
功能安全的思路是自顶向下的:先识别危害(如「非预期加速」),评估严重度、暴露概率、可控性,定出安全目标和完整性等级(汽车里叫 ASIL,从 A 到 D 越来越严);再给每个目标设计安全机制,并规定出故障时退到哪个安全状态。
关键的一刀是随机失效 vs 系统性失效。硬件元件会随机损坏,可以用失效率做冗余计算;软件不会磨损,它的缺陷在写下那一刻就存在,同样输入、同样时序下必然重现。所以标准对软件不要求算概率,而是用过程严谨度兜底:等级越高,要求的评审、测试覆盖、工具鉴定越多。这也意味着:软件出没出问题,只能靠证据而不是计算来回答——这正是实验的用武之地。
失效模式与影响分析(Failure Mode and Effects Analysis,FMEA)是功能安全最常用的工具之一,方向和故障树相反:自底向上。逐个组件问四件事:它可能怎么失效(失效模式)?局部会怎样?传到系统层会怎样?现有什么手段能发现或缓解?
每一行再打三个 1–10 分:严重度(S)、发生度(O)、可探测度(D,越难发现分越高),相乘得到风险优先数 RPN = S × O × D(1 到 1000)。白话:后果越重、越常发生、越难察觉的坏法,越该先治。
作者对 FMEA 的评价是双面的。它的价值:强迫团队系统性地思考失效,产出一份「我们认为系统会怎么坏、我们打算怎么应对」的清单。它的局限:
本章的核心论点:FMEA 的每一行,本质上都是一个未经验证的假设。「GPS 丢失 → 系统切换到惯性导航并在规定时间内提示驾驶员」——这是一个可以被实验检验的稳态假设,正好是混沌工程的输入格式。
于是两者形成闭环:FMEA 给出值得测的失效模式与预期缓解;混沌实验真正注入该故障,观察缓解是否生效、多快生效、有没有出现表里没写的连锁影响;结果回写 FMEA——修正严重度和可探测度、补上新发现的失效模式。FMEA 从一次性文档变成被实验持续校准的活文档,而混沌工程也从「随机找弱点」变成有安全分析指路的定向实验。
这并非凭空嫁接:故障注入在安全领域本就是公认手段,ISO 26262 就把故障注入测试列为推荐的验证方法之一。区别在于用法——传统上它常被当作确认性测试(证明设计的机制能触发),混沌工程的姿态是探索性实验(去发现你没想到的行为)。
CPS 大多是实时系统:控制回路每几毫秒必须完成一轮,时间本身就是正确性的一部分。这带来一个 Web 世界很少遇到的麻烦——探针效应(probe effect):为了观测或注入故障而加的代码,会占用 CPU、改变调度和时序,从而改变被测系统的行为。加一行日志,竞态 bug 可能消失;去掉日志,它又回来。你实验验证的,可能已经不是你要交付的那个系统。
应对思路的共同点是别让「测试版」和「交付版」分叉:把观测与故障注入钩子设计成产品的常驻部分、默认关闭但随产品一起交付和认证;尽量用低开销或硬件辅助的追踪;并量化探针自身开销,纳入时序分析。
CPS 里做混沌实验,核心取舍是实验真实度 vs 伤害风险。Web 世界用「流量百分比」量爆炸半径,这里要用「最坏会伤到谁」来量。
实验放在哪一级(量级为示意)
| 层级 | 真实度 | 单次成本 | 能发现 | 代价 / 盲区 |
|---|---|---|---|---|
| 纯仿真 / 软件在环 | 低–中 | 极低,可并行跑成千上万次 | 逻辑与状态机缺陷、组合场景 | 模型与现实的差距;时序不真实 |
| HIL 台架 | 中–高 | 中,台架数量有限 | 真实控制器的时序、驱动、总线问题 | 环境仍是模拟的;台架昂贵 |
| 封闭场地 | 高 | 高,每次要人、车、场地 | 传感器噪声、机械与环境交互 | 场景有限;仍需安全员与独立急停 |
| 受控实地 / 车队 | 最高 | 极高 | 真实长尾 | 伤害可能不可逆;只在安全状态有独立保障时考虑 |
三种「想故障」的方法
| 方法 | 方向 | 擅长 | 盲区 |
|---|---|---|---|
| FMEA | 自底向上:组件 → 影响 | 系统性列全单点失效、排优先级 | 交互故障、多故障叠加;软件发生度靠猜 |
| FTA 故障树 | 自顶向下:事故 → 原因组合 | 分析某个严重事故的所有路径 | 只看预先选定的顶层事件;仍靠想象 |
| 混沌实验 | 经验式:注入 → 观察 | 验证缓解真的生效、暴露未知行为 | 只能测能安全复现的条件;受探针效应影响 |
判据:用 FMEA / FTA 决定测什么,用实验决定信不信;实验从最便宜、最安全的一级起步,只有当下一级有独立于被测系统的中止与安全状态保障时才往上走。
自动驾驶、无人机、机器人、医疗器械(IEC 62304)、工业控制都在快速软件化,越来越多后端工程师会写进控制回路的代码。架构评审被问「这个降级方案你怎么知道它有效」时,本章给的回答是:FMEA 里写着有效,台架实验证明过它有效,而且结果已回写表格。
大厂实证
failure 命令的说明写着「Inject failures into system.」,示例是「Test the GPS failsafe by stopping GPS」,可注入 GPS、电池、电机等组件的 off / stuck / garbage / delayed 等失效;且默认被参数 SYS_FAILURE_EN 关闭——注入能力常驻、但要显式开启。PX4 Autopilot · failure 命令源码(github.com/PX4/PX4-Autopilot)① CPS 里故障的代价是人身伤害,混沌工程的执行方式必须改变,但原则不变。
② 功能安全早已系统研究失效:危害分析、安全目标、安全状态、完整性等级。
③ 硬件失效是随机的、可估概率;软件失效是系统性的,只能靠证据回答。
④ FMEA 自底向上列失效模式,RPN = S × O × D 排优先级;盲区是交互故障与多故障。
⑤ 核心论点:FMEA 每一行都是待验证的假设,混沌实验来证实,结果回写成活文档。
⑥ 实验沿仿真 → HIL → 封闭场地 → 受控实地逐级上行,每一级都要独立中止保障。
⑦ 探针效应:观测会改变实时系统的时序;让轻量探针常驻交付版本、开销计入预算。
⑧ 实证:PX4 内置故障注入;火星探路者靠常驻追踪排障;Uber 事故是缺少独立兜底的反例。