专业书籍精读 · Chaos Engineering · 第 2 章
Chaos Engineering: System Resiliency in Practice · Ch 2 · Casey Rosenthal & Nora Jones · 2020
上一章说的是:现在的线上系统太复杂,没人装得下,所以故障推不出来。这一章接着问一个更扎心的问题——既然没有人想出事,为什么系统还是会一步步走到出事那天?答案不是「有人偷懒」。真正的答案更难受:每天把它往危险处推的那几股力,本身全是正当的。
你开车跑一趟长途,身上有三条看不见的绳子在拽着你:
你一天下来大概会在「不太费油、不太累、还没出事」之间找个舒服点。问题出在这儿:前两条绳子你拉过头会立刻难受——油表掉得快你看得见,困了你自己知道。安全这条不一样:超速跟车一百次都没事,第一百零一次才出事。它平时一声不响,只在越过的那一瞬间给你一记重击。
一个团队也是这样。省成本(关掉备用机器)有人表扬;少折腾(这季度演练先不做了)大家都轻松;而「你们这么干已经很危险了」没有任何人会告诉你——因为它上一百次都没出事。所以不是某天突然变危险的,是天天往那边挪一点,每一步都看着没毛病。最要命的是:等你终于收到安全那条绳子的反馈,那个反馈的名字就叫「事故」。
想不漂过去,就得让安全这条绳子平时也会说话。办法是:主动在可控范围里制造一次小故障,看系统真实怎么反应。这相当于在空旷场地上试一次急刹——提前知道自己离失控还有多远,而不是在高速上第一次知道。这就是混沌工程在这套模型里的全部作用:它不是来找 bug 的,是来替安全那条边界喊疼的。
这一章还数了数复杂到底从哪来,一共四处:系统有多少种可能的情形、零件之间有多少条牵连、外头有多少你管不着的东西、以及出事之后撤不撤得回来。前三处都是业务要的——多做一个功能就多一堆情形,多接一个合作方就多一堆牵连,用户和市场本来就不听你的。能真正当工程目标的只剩最后一个:出错之后多快能回到原样。这也是为什么业界这些年把大钱花在「一键撤回、先放给一小撮人试、随时能关」上,而不是花在「这次保证不出错」上。诚实说一句代价:这些本事本身也要花钱,而且它们只能让你出错后损失变小,不能让你不出错。
系统不是某天突然变危险的,是被几股正当的力气天天往危险处推一点;三条边界里只有安全那条不会提前喊疼,混沌工程就是替它喊。
想进到具体机制、量级和示意图? → 切到精读版
你以为事故的起点是「某个人犯了错」。这一章要换掉的正是这个起点:把系统推向失效的三股力——省成本、省力气、追业务——每一股单独看都完全正当,而三条边界里只有「安全」这一条不会在越界之前给你任何疼痛反馈。于是漂移(drift)不是失职,是这套受力结构的必然解。本章用两个模型把 Ch1 的「推不出来」升级成「所以必须亲手造一个安全信号」——这就是混沌工程存在的理由本身。
全书 21 章的第 2 章,Part I「铺垫」的中间一章,是 Ch1 与 Ch3 之间的桥:Ch1 的前提是「复杂系统推不出来」,Ch3 才给五条原则,这一章回答中间那个问题——那系统为什么还会越来越危险、我该把力气花在哪。动态安全模型并非凭空发明,它来自 Rasmussen 的韧性工程,本章把它搬进软件语境。现实里它对着的,是任何一个「长期没出事、于是不断砍冗余和演练」的组织。
Ch1 证明了「整体行为推不出来」,但留下一个洞:如果没人动手破坏它,系统为什么会自己变危险?
这个洞不填,你会得出一个很贵的结论:长期没出事 = 当前很安全。把场景摆具体就知道有多贵。某个服务跑了 18 个月零事故,于是四件事顺理成章地发生了:备用区域常备容量从 100% 降到 30%(一年省掉七位数机器钱,而且「反正从没切过」);季度故障演练因挤占迭代被取消;超时与重试参数是三年前设的,再没人核过;熔断器配好了但从没真跳过。
这四个决定里没有一个是错的。每个都有当期收益、都有数据支持——确实省钱了、确实多发了功能、确实 18 个月没出事。
然后真正的区域故障来了。30% 常备容量要接住 100% 流量,扩容需要几分钟;这几分钟里重试风暴先把剩下的容量打满;熔断器第一次真跳,它的半开探测又把刚缓过来的下游打死一次。一次事故把四个「正确决定」同时结清。
本章要解决的就是这个:给出「系统为什么会漂」的受力机制,以及工程上该在哪里加反向力。不解决会怎样——可靠性预算永远在事故后一个月最充足、之后逐月被蚕食,然后周期性撞墙。
本章把 Rasmussen 的模型改写成一个很好记的画面:一个工程师站在中间,被三根橡皮筋分别拴向经济(Economics)、工作量(Workload)、安全(Safety)三个方向。他可以在这个空间里走动、把橡皮筋拉长;但离某个方向太远,那根就会崩断。三根断掉分别长这样:
关键的不对称在这里:经济和工作量这两根在崩断之前就一直在拉你——成本报表每月提醒一次,on-call 疲劳每周提醒一次,疼痛连续且即时。安全这根没有。你可以朝它的反方向走很久,它一声不响,直到崩断。
把这条不对称翻译成受力分析,就是本章最硬的结论:三个方向里有两个有稳定的梯度把你往外推,只有安全方向缺一股把你拉回来的反向梯度。
两股常在的力,加一股只在事故后短暂出现的力,合力方向只有一个。所以漂移不是失职,是这套受力结构的必然解——这直接推翻了复盘会上那句「他本该更小心」:在唯独安全方向缺反馈的系统里,「更小心」是个没有支点的要求。它还解释了一个常见现象:可靠性投入曲线总是锯齿形的。大事故后拿到预算和注意力,接着 6–12 个月被成本与交付节奏逐月蚕食,然后再撞一次。锯齿不是文化问题,是缺反向梯度的几何结果。
于是本章给混沌工程一个很精确的定位——它不是用来找 bug 的,是用来给安全边界装一个平时也能感知的信号。
机制说白了:在可控条件下主动制造一次故障,系统的真实反应就是一次对「我离安全边界还有多远」的测量。它把安全从「只在越界那刻出现的离散事件」变成平时就读得到的连续量——那根一直缺着的反向梯度。
落到具体:一次计划内的区域撤离演练,测出 30% 常备容量下扩容要 7 分钟,而重试风暴 40 秒就能把剩余容量打满。这两个数字现在和成本报表上的数字处在同一张桌子上、可以吵架了。安全之所以在预算会上总输,不是因为大家不重视,而是它过去拿不出和成本、交付同量纲的数字。
诚实补一句代价:这根梯度是花钱买来的——演练占人力、占环境,在生产上做就一定波及一部分真实用户;Ch4 到 Ch8 大半篇幅都在讲怎么把这部分代价压到最小。
本章第二个模型回答另一个问题:既然复杂度削不干净(Ch1 的结论),它到底由什么撑着?四根柱子:
n(n-1)/2(任取两个配成一对的数量)平方涨。叫「经济支柱」是因为前三根的高度不由工程决定,是业务买单换来的:多一个功能 = 多一堆状态,多接一个渠道 = 多一堆关系,进一个新市场 = 多一片环境。它们涨恰恰说明产品在成功——这正是 Ch1 那句「复杂度是成功的副产品」。
本章的实操结论很锐利:前三根你只能被动接受,第四根才是你真正的杠杆。
顺着可逆性排,该买什么就清楚了:一键回滚、不可变部署(immutable deployment,新版本另起一批机器而不是原地改)、金丝雀发布、功能开关(出事直接关掉这个功能,不必回滚整版)、蓝绿切换、数据迁移先双写再切读。它们解决的都不是「这次别出错」,而是「出错后 2 分钟内回到原样」。
最容易被跳过的要点:可逆性必须被验证过才算存在。没执行过的回滚脚本、没真切过的灾备区域、配好但没跳过的熔断器,账面上都算可逆性,实际全是未验证的假设。这正是混沌工程和这根柱子接上的地方——演练就是在量它的真实高度。
另一个常被忽略的形态:可逆性不只在部署层,也在请求层。撑不住时主动砍掉推荐、评论、个性化,只保住下单主干——优雅降级就是在请求层临时把状态空间收窄、把关系数砍掉。
三条边界的对策,核心差别在「平时有没有反馈」:
| 边界 | 越界长什么样 | 平时有反馈吗 | 反向力从哪来 | 代价 / 失效点 |
|---|---|---|---|---|
| 经济 | 可靠性投入被成本评审砍掉,或公司没活到用上它 | 有,成本报表每月 | 不用造,天然过剩 | 省过头会把安全余量当浪费删掉 |
| 工作量 | 流程被悄悄旁路、人员流失 | 有,on-call 疲劳每周 | 不用造,天然过剩 | 隐蔽:看板上像「都遵守」,实际是绕过 |
| 安全 | 事故 | 没有,越界那刻才知道 | 只能人工造:混沌实验、错误预算、定期演练 | 花人力与环境,生产实验必波及真实用户 |
全部信息量在第三列:三条边界里只有一条需要你花钱给它装一个仪表。
四根支柱怎么处理,决定了工程预算该往哪投:
| 支柱 | 谁在推高它 | 工程能压吗 | 该怎么做 |
|---|---|---|---|
| 状态 | 功能、开关、配置、数据形态 | 几乎不能,压它等于删功能 | 收敛配置来源、消掉隐式状态;接受它会涨 |
| 关系 | 拆服务、接第三方、复用平台 | 有限,拆和合都有代价 | 画清关键路径、标出哪些依赖真的不可或缺 |
| 环境 | 用户、市场、云厂商、监管 | 不能 | 只能假设它会变坏,并为此准备 |
| 可逆性 | 没人会自动推高它 | 能,而且是唯一能的 | 把预算压在这里:回滚、金丝雀、开关、降级——并且逐条验证过 |
什么场景该怎么选,判据可以落得很具体:
这一章最实用的产出是一句能在成本评审会上用的话:「我们 18 个月没出事」不是安全的证据,只是「还没越界」的证据。面试被问「你怎么推动可靠性投入」,答「把安全变成和成本同量纲的数字——错误预算,加演练测出的真实恢复时间」,比答「我会强调可靠性很重要」高一个层级。
大厂实证
① 核心命题:系统持续向失效边界漂移,推它过去的三股力(省成本、省力气、追业务)每一股都正当。
② 动态安全模型(改写自 Rasmussen):工程师被经济、工作量、安全三根橡皮筋拴着,离任一方向太远那根就崩断。
③ 关键不对称:经济与工作量在崩断前一直有疼痛反馈(成本报表、on-call 疲劳),安全没有——它只在越界那刻说话。
④ 漂移是受力结构的必然解,不是谁的失职;可靠性投入曲线呈锯齿形是同一个原因。
⑤ 混沌工程的定位:不是找 bug,是给安全方向装上那根缺失的反向梯度,让它拿得出和成本同量纲的数字。
⑥ 复杂度的四根经济支柱:状态、关系、环境、可逆性;前三根由业务买单推高,是成功的副产品。
⑦ 可逆性是唯一能当工程目标的那根——回滚、不可变部署、金丝雀、开关、降级,买的都是「出错后多快回到原样」。
⑧ 未验证过的可逆性等于没有:没执行过的回滚脚本、没切过的灾备、没跳过的熔断器都只是假设。
⑨ 「N 个月零事故」不是安全证据,只是「还没越界」的证据;工作量边界的失效形态最隐蔽——不是大家更谨慎,而是流程被悄悄旁路。