喵喵队里最招人烦的一只猫,是演习猫。
别的猫都在等真出事的时候上场救火,只有它没事就跑来拆东西:把备用电源的插头拔掉、把服务器机房的空调关掉、把队友的对讲机偷偷调成静音,然后蹲在一边,抱着爪子看你们手忙脚乱。第一次见它这么干的猫都想咬它。可队长知道,正是这只讨厌的猫,让整支队伍在真正的灾难来临时,一次都没垮过。
它信奉一句话:一个你从来没在它坏掉时练习过的系统,你根本不知道它坏了会怎样。
什么是「平时把它弄坏」
先把这只猫的手艺起个正经名字。
混沌工程,说人话就是:趁系统还活着、还有人盯着的时候,主动往里面注入故障——拔掉一台机器、掐断一条网线、让某个服务变慢——看看整个系统会不会因此垮掉。它不是等故障自己来,而是自己制造小故障,把真故障来临前的那次崩溃,提前挪到一个你有准备、有退路的下午。
就像你搬新家,不会等半夜真着火了才去找灭火器在哪。你会挑个白天,故意假设「厨房着火了」,然后从沙发走到灭火器、再走到门口,走一遍。走这一遍的目的,不是为了今天灭火,是为了确认:灭火器真的在、真的能拿到、路上没堆着杂物挡道。
这里面藏着一个特别反直觉的点,值得单独说:你想让系统更稳,办法居然是主动去搞乱它。这听着像自相矛盾,其实一点都不。
为什么「不弄坏」反而更危险
一个从来没坏过的系统,不代表它结实,只代表它运气还没用完。
问题出在人性和工程的一个通病:那些「出事时才会用到」的东西,平时没人管它到底好不好使。备用发电机、故障切换开关、灾备机房、错误处理的那段代码——它们是消防栓,一年到头没人碰。而没人碰的东西,会悄悄坏掉。
这里有个专门的词。潜伏故障——一个已经坏了、但因为暂时没被用到、所以谁都没发现的故障。它就像你家那个卡住的备用手电筒:平时不用,你以为它好好的;等真停电了摸黑去拿,一按,不亮。它不是那一刻才坏的,它早就坏了,只是那一刻你才发现。
系统里最可怕的不是「会坏的东西」,而是「你以为不会坏、其实早坏了、但你一直没发现」的东西。备胎瘪了三个月你不知道,直到某个雨夜正胎爆了,你打开后备箱——两个都不能用。
演习猫存在的全部意义,就是把潜伏故障从阴影里揪出来。它平时就去拔那个备用电源,于是它会发现:哦,原来切换过去要 40 秒,这 40 秒里网站是白屏的;哦,原来备用机房的证书三个月前就过期了;哦,原来那段「捕获错误」的代码本身就有 bug,一遇到真错误自己先崩了。这些事,你要么现在在可控的下午发现,要么将来在最糟的凌晨三点发现。没有第三种可能。
它到底怎么运作:先立护栏,再放猴子
混沌工程不是瞎砸。乱砸叫破坏,不叫工程。真正的做法有一套规矩,核心就四步。
1. 先定义「正常长什么样」
动手之前,你得先知道系统健康时的样子:每秒处理多少订单、响应多快、错误率多低。这叫稳态——系统正常运转时那些指标该有的、稳定的数值。没有这条基准线,你注入故障后就没法判断「变糟了没有」。
2. 大胆假设「如果……会怎样」
提一个具体问题:如果这台数据库突然消失,用户还能下单吗?好的假设是能被证伪的,不是「应该没事吧」这种许愿。
3. 注入真实的故障,但先关小水龙头
然后真的去干——但从最小的范围开始,且随时能一键停手。这是这只猫和纯粹搞破坏的猫最大的区别:它手里永远攥着一个「爆炸半径」的旋钮。
爆炸半径,就是「万一这次演习真把事情搞砸了,最多能波及多大范围」。先只拿 1% 的用户试,别一上来就全站。这样即使假设错了、系统真扛不住,受伤的也只是一小块,而且你手边就有开关能立刻叫停。
4. 对比稳态,看差距
故障注进去了,回头看指标:还在稳态附近吗?如果在,恭喜,你现在有证据证明系统扛得住这种故障——不是「我觉得能扛」,是「我拔过,它没倒」。如果不在,你就抓到了一个真 bug,而且是在可控环境里抓到的。
这套方法最有名的一次落地,来自一家在线看电影的公司。他们养了一只软件做的「捣乱猴子」,叫 Chaos Monkey(混沌猴)——一个会在工作时间随机挑一台正在服役的服务器、直接把它关掉的小程序。注意是工作时间、是生产环境、是真在干活的机器。它的逻辑很暴力也很干净:既然机器早晚会随机挂掉,那就让它天天挂给你看,逼着每个工程师从第一天起就把系统写成「死一台没人在乎」的样子。疼一次就长记性,天天疼就再也不敢写出那种「死一台就全崩」的脆弱结构。
脆弱、坚韧、反脆弱:三种东西被折腾后的下场
讲到这,得引入这只猫真正想让你懂的一个分类。同样是「被折腾」,不同的东西反应天差地别,大致分三档。
- 脆弱:一折腾就坏,且越折腾越坏。玻璃杯、瓷器、没做过演习的系统。冲击对它只有害处,它最怕的就是变化和意外。
- 坚韧:折腾它,它不坏,但也不会变得更好,顶多是「扛住了」。石头、防摔的手机壳。冲击对它无所谓,但它也没从冲击里学到东西。
- 反脆弱:这是最反直觉的一档——适度折腾它,它反而变得更强。冲击对它是营养,不是伤害。
「反脆弱」是个新造的词,因为「脆弱」的反义词一直是空缺的。大多数人以为脆弱的反义是「结实」,但结实只是「不怕摔」,它没说「摔了会更好」。真正的反面,是那种「你越摔它、它越结实」的东西。这个词就是专门造来指这种东西的。
什么东西是反脆弱的?你的身体就是。
你去健身房举铁,本质上是在主动给肌肉制造微小的损伤——举重会撕裂肌肉纤维。如果肌肉是脆弱的,你越练它越废。但肌肉是反脆弱的:身体感知到「这点力量不够用」,于是在修复时把纤维长得比原来更粗更强。骨骼也一样,适度的压力刺激会让它长得更密。免疫系统更是如此——小时候接触点脏东西、打疫苗(疫苗就是一小份被削弱的病原体,等于给免疫系统做的一次安全演习),免疫系统见识过了,真敌人来了就认得。
反过来,一个被过度保护、从没受过任何刺激的身体,是脆弱的。宇航员在失重环境里待久了,骨头因为不再承受体重的压力,会变脆、流失钙质。肌肉不用则废。把冲击彻底拿走,不会让一个反脆弱的系统更安全,反而会让它退化成脆弱的。
看出这只猫的深意了吗。它平时来拆你的系统,不只是为了「检查有没有坏」——那只是把系统练成「坚韧」。它真正想要的,是让整支喵喵队变成反脆弱的:每被它折腾一次,就补一个洞、加一层保险、写一条新规矩,下次同样的冲击来,队伍不但不倒,还比上次更稳。系统在一次次可控的小疼里,长成了扛得住大疼的样子。
不止是软件:全人类都在偷偷做演习
这套「平时把它弄坏」的思路,远不止软件工程师在用。
你上学时经历的消防演习就是。没有真的火,但铃一响,全楼的人真的要放下手里的事、按疏散路线走到操场集合。为什么要浪费这半小时?因为真着火时,人是会懵的,会往自己进来的门跑(那往往是最堵的),会忘记楼梯在哪。演习把「逃生」这件事从需要临场思考的事,变成了身体记得的肌肉反应。等真出事,你不需要冷静——你的腿已经知道往哪走。
航空业更狠。飞行员的执照不是考完就一劳永逸,他们要定期回到飞行模拟器里,被教官反复灌各种要命的故障:发动机在起飞最关键那一刻熄火、仪表全部失灵、遇到风切变。在模拟器里,飞行员可以「坠机」一百次,每次都从头再来。于是当极小概率的真故障发生在三万英尺高空时,飞行员的反应不是恐慌,而是「这个我在模拟器里练过八十遍了」。他们把一辈子可能只遇到一次的灾难,在安全的地面上提前经历了很多次。
还有电网、医院、核电站——所有「一旦真崩后果严重」的系统,背后都藏着一只演习猫,逼着他们在没出事的时候,一遍遍排练出事。
它留给下一章的一个刺
不过,演习猫也有它挠头的时候。
它能拔掉一台机器、能掐断一条线、能模拟一场火。可有些灾难,不是「一个零件坏了」那么简单——是无数个各自都好好的零件,因为彼此纠缠、互相拖累,在某个说不清的临界点上,突然一起雪崩。这种崩溃,你没法靠拔掉某一台机器来预演,因为坏的不是任何一台机器,坏的是它们连在一起时那个「整体」。
演习猫能让每个零件都变得反脆弱,但整支队伍拧在一起、又要面对一场谁都没排练过的、系统级的大危机时——那些单独看都做对了的机制,怎么叠加、怎么协同,才能真的顶住?
这,就是最后一章,收队的时候,队长要回答的问题了。