▶ Cinematic fable · Watch on YouTube ▶ 影片版寓言 · 在 YouTube 观看
临河有一处染坊,叫万青坊。
坊有三进院子:第一进井院,第二进媒染院,第三进染院。院墙矮,从河上过船能看见里面一排排染缸,缸沿上浮着一层靛青,太阳一照,像一排小小的深潭。
万青坊有一条规矩,外乡人第一次来听见,都要愣一下。
缸翻了,不许捞。
染一缸布要三天。第三天早上开缸,水色要正得像一口井。若是歪了——发灰、发绿、发浑,或者最怕的那种:看着对,摸着也对,只是凑近了闻,有一丝酸——这缸布就是废的。
废了怎么办?
新来的学徒第一个反应都一样:捞出来,投进清水里洗一遍,重新下一把靛,再压半斤石灰盖住酸味。三天,四十匹布,总能救回大半。
老师傅的回答永远是同一个动作。
他走过来,低头看一眼缸,然后把缸掀翻。
水泼进沟里,布拖去晾干,当抹布。缸刷净,从井里重新打水,从柜上重新取靛,从第一天的第一道工序重新开始。
三天,四十匹布,倒进沟里。
学徒疼得说不出话。
老师傅只说一句话。这句话,万青坊传了七代:
半坏的缸,比翻了的缸贵。
—
这句话,阿绫用了三年才明白。
她来的第一年,跟着三师父看缸。三师父话极少,只教了一件事:看缸的时候不许动手。
“你看着就行。”三师父说,”歪了,报我。别搅,别加水,别去补。”
阿绫问为什么。
三师父说:你搅一下,它就变成另一个东西了。它本来是要翻的,翻了我知道,我重下一缸。你搅了它,它不翻了,可它也不是原来那一缸了——它会染出一批看着很好的布,卖出去,穿三个月,褪成一身花斑。到那时候来找你的不是三师父,是全城的客人。
那一年,阿绫记下了三十七次翻缸。
每一次,三师父都在墙上那块木牌上刻一行:日子、缸号、翻缸的时辰、为什么歪。刻完了,才重新打水。
阿绫问:刻这个做什么?反正都翻了。
三师父说:翻一次是意外。翻十次是话。
—
第二年开春,井院出了事。
媒染院配灰水的水,是从井院挑的。那口井吃了两场春雨,水里带进来一点铁。铁不多,人喝不出来;可灰水一沾铁,染出来的青就发暗。
先是七号缸翻。
三师父掀了,重下。
第二天,七号缸又翻。
三师父又掀了。第三天早上,七号缸第三次翻。
这一次,三师父没有去掀缸。他解下腰间的红布,走到媒染院门口,把红布系在了门环上。
红布一系,媒染院停了。
阿绫急了:一院子的布都泡在缸里,停一天,多贵?
三师父说:一根缸翻三次,就不是缸的事了。
他说:第一次我以为是手;第二次我以为是靛;第三次我知道,我不认识它。我不认识的东西,掀一百次也还是掀一百次。掀缸是我会的事;找出井里的铁,不是我会的事。所以我把它交上去。
红布交到了大掌柜手里。
大掌柜没有掀缸,也没有骂人。他做了另一件事:把这三天的木牌全调来,摆在桌上,一张一张地对。
对到第九张,他抬头了。这三天翻缸的,不止七号。还有二号、十一号、十四号——翻的都沾过媒染院的灰水。
于是他去查井。
查出来是院墙根底下裂了一道缝,雨水裹着墙土渗了进去。补墙,淘井,媒染院重新开张。
那天下午,阿绫站在井院门口,盯着那块红布看了很久。
她问三师父:要是第三次您还掀呢?
三师父说:那我就掀到死。一直掀缸的人,永远查不到井。
—
后来阿绫才知道,这坊里的规矩,比她看见的要细得多。
井院、媒染院、染院——这个顺序不是随便排的。开坊要点火,得照这个顺序;收坊要熄火,得倒过来。因为后头的院子靠前头的院子活着:媒染院没有灰水,染院开不了;染院开不了,晒场没东西可晒。
缸翻了,掀到哪一层,也看这个顺序。
有的时候,只掀那一根缸。这叫换一根。
有的时候,是媒染院某根缸配的东西坏了,那就不能只掀那一根——从这一根往后、按开坊顺序排在它后面的所有缸,全掀。因为后面那些缸,用的都是前面这根配出来的东西。这叫换这一根和它后面的。
还有的时候,比如染院的色头缸歪了,整个染院一起掀。色头缸定的是全院一年的色;它歪了,别的缸里那些”看着差不多”的色,就全不算数了。这叫换一院。
三种掀法,哪一种,写在缸边的木牌上,不许临场想。
阿绫问大掌柜:为什么不干脆每次都掀一院?反正最稳。
大掌柜笑了:一年掀三百次院,你替我出布钱?
—
还有一件事,阿绫是后来才注意到的。
不是所有缸翻了都要重下。
井院那口井的缸,是死的:一年四季不歇,翻了一定重下。
靛青的季节缸,是活的:正染着的时候翻了,重下;收工以后才翻的,就不下,等下一个季节。
试色的那一缸,是一次的:翻了就翻了,从不重下。它本来就是拿来看一眼的,看一眼就够了。
大掌柜说:把这三样分清,一年能省一半的靛。
还有熄火。院长从不砸缸。他往下喊一声,缸主自己把缸刷干净、把火压灭。喊过十声没人应,院长才动手敲缸。
阿绫问:为什么不直接砸?快。
大掌柜说:砸一根缸,满院子都是碎片。碎渣子掉进别的缸里,你明天还得再掀三根。
—
再有一条规矩,是阿绫觉得最不讲道理的那一条。
一个院,一个时辰里掀三根缸,院长就得停院。
不是”再看看吧”,不是”再撑一撑”。就是停。门环系红布,人站到院子里,等大掌柜。
阿绫问:万一第四根缸本来是好的呢?
大掌柜说:那它就白翻了。我认。
阿绫问:那为什么是三根?为什么是一个时辰?
大掌柜说:因为这三个数,是我拿七代人的账本试出来的。数字本身不重要。重要的是它有个数。
他说:一个心里没数的院长,会把一辈子花在掀缸上。他会掀得很勤,很辛苦,很像个能干的人。而真正坏了的那口井,永远没人去看。
—
第三年冬天,阿绫第一次自己当院长。
她管晒场。最末一进,最轻的一进。晒场的活儿简单:布从染院抬来,摊上竹架,看天收布。
她整个晒场,只有一张竹架是她的。
头一个月,她掀了两次。
第一次是风大,竹架连着布一起倒进了泥里。她把布卷起来,回染院重领。
第二次是她自己病了三天,回来的时候布已经晒过了头,硬得能立起来。她把布卷起来,回染院重领。
两次她都做对了。
第三个月,出事了。
连着下半个月的雪,晒场收了四十架布,全堆在屋里。屋里生着炭,炭气闷着不散,布上起了一点黄斑。
阿绫的第一反应,是把带黄斑的那几匹挑出来,单独挂到风口上,看能不能吹掉。
她蹲在布堆前,挑了两个时辰。
挑到第三十七匹的时候,她忽然停了手。
她想起三师父那句话:你搅一下,它就变成另一个东西了。
她站起来,把那四十架布一匹一匹记进账,然后去敲大掌柜的门。
她说:我把晒场掀了。
大掌柜正在喝粥,抬起头:全掀?
阿绫说:全掀。黄斑不是我挑得干净的。我挑了两个时辰,挑出来的都是看得见的;那看不见的,会在客人的衣柜里长出来。
大掌柜放下碗,看了她很久。
然后他说:今晚到我屋里来。我给你看账本。
—
那天夜里,大掌柜摊开了一本很旧的册子。
册子上画着一棵树。可它不像树,倒像一座倒过来的坊:底下是一横,横上伸出三根叉,每根叉上又伸出几根线。
大掌柜说:这是万青坊的根。
最上面那一横,是他自己。底下的三根叉,是三个院的院长。每个院长底下,是各自院里的缸。缸底下要是还有东西——比如染院里管火的那口灶——灶自己也有自己的小册子,画着它底下那几根柴。
阿绫说:那我呢?
大掌柜指了指最边上的一根线:你在这儿。你上头是晒场。晒场翻了,我知道;晒场撑不住了,我知道了就得动;我撑不住了——
他停了停。
我撑不住了,坊就关了。
阿绫问:关坊是什么样子?
大掌柜说:关坊不是塌。关坊是我一根一根地熄火,从上往下,谁都不许自己熄。熄到最后一口灶,我锁门。
他说:我在这个位子上,一年也掀不了两根缸。我哪天要是也开始掀缸了,那就是坊要关了。
阿绫问:为什么您掀不了?
大掌柜说:因为我不该有缸。
他说:你看我这屋里有什么?一盏灯,一本账,一把井匙。我没有缸,我就没有会歪的东西。我这辈子唯一的活儿,是谁翻了、谁该掀、掀到哪一层。这活儿看着轻,其实最重——所以上面不能放别的东西。
—
阿绫后来也老了。
有人问她:万青坊为什么一百年不倒?
她说:因为它不怕翻缸。
问的人说:哪家染坊不怕翻缸?
阿绫说:不怕翻缸的染坊很多。万青坊不一样的地方是——它不怕自己救不回来。
她说:一根缸废了,我掀了重下。一根缸一连掀三次,院长就把院停了。一个院停了三次,我就把坊停了。我从来不知道下一次翻缸要花多少钱,我只知道每一次翻缸,都往上走一层。往上走的那一层,比底下那一层多点东西——多一口井,多一本账,多一双没有缸的手。
所以问题总在它还小的时候,被交到一个能看见它的人手里。
阿绫最后说了一句话,刻在井院的墙上:
会救的,救一匹布。 会掀的,救一座坊。
— —
By now you’ve probably recognized it: this is the Erlang/OTP supervision tree — the architecture behind the doctrine called let it crash.
这是什么
Erlang 的并发单位是进程(process):极轻、单线程、堆独立、不共享内存。两个进程之间没有指针可以互指,只有消息。这个设计带来一个后果,也是整套容错体系的起点:
一个进程崩溃,不可能弄坏另一个进程的数据。
于是 Erlang 的写法与主流相反。主流是在每个函数里预判所有失败、层层兜底、把异常状态就地修补;Erlang 的口号是 let it crash——不要在业务代码里写恢复逻辑,让进程干脆地死掉,从干净的初始状态重来。理由是:一个”半坏但还在跑”的进程,会持续产出看起来正常的结果,而这些结果无法与正常结果区分。死掉的进程至少是诚实的。
链接(link)把两个进程的生死绑在一起:一方异常退出,另一方会收到一个退出信号(exit signal)。监控者(monitor)是单向版本,只通知,不连坐。
监督者(supervisor)就是一个只做三件事的进程:按顺序启动子进程、监视它们的退出、按策略重启它们。 它自己不干活。子进程的规格叫 child spec,里面写明启动方式、重启类型、关机超时。
重启策略有三种,对应真正的依赖结构:
one_for_one:只重启挂掉的那一个。rest_for_one:重启挂掉的那一个,以及按启动顺序排在它后面的所有子进程——因为后面那些依赖前面的。one_for_all:一个挂了,全部杀掉重来——因为它们必须处于同一代状态。
重启类型(restart type)有三种:permanent(永远重启)、transient(异常退出才重启,正常退出不重启)、temporary(永不重启)。
重启强度(restart intensity)是整套机制的安全阀:每个监督者配 max_restarts 与 max_seconds。若在时间窗内重启次数超限,监督者不再重启,而是自己终止——把问题交给它的上级监督者。上级有更大的时间窗、更宽的视野、更少的工作负载。若根监督者也超限,整个应用终止。
错误内核(error kernel)是随之而来的设计原则:越靠近树顶的组件,做的事越少。 顶层只保留极少、极稳、绝不该重启的逻辑(配置、注册表、连接池的簿记),所有有风险的、会崩的、逻辑复杂的活儿,统统推到叶子节点。崩溃的成本因此被限制在树的低层,而树顶有足够的上下文去判断”这到底是不是井的问题”。
此外还有:有序启动、逆序关机;关机时先发 shutdown 并等待超时,超时才 brutal_kill;注册名使客户端在重启后仍能按名字找到服务,而不必追 pid;以及每一次崩溃都会生成一份 crash report,带完整退出原因与调用栈。
为什么重要
- 它把”容错”从预测变成了结构。 传统写法要求你预判失败模式并各写一段恢复代码,而失败模式是无穷的。监督树的做法是承认自己预测不了:把故障域切小,让崩溃廉价,让重启快。Erlang 生态里那句”九个九”(99.9999999%)的可用性说法,靠的不是更聪明的恢复逻辑,而是”崩了就重来”的算术。
- 重启强度限定了失败会走多远。 没有
max_restarts的自动重启系统会陷入重启风暴:一个永久性缺陷被无限重试掩埋,系统看着在自愈,实际在空转。强度超限后监督者主动退出,这不是放弃,而是把决策权交给拥有更多信息的上一层——叶子只会掀缸,树顶才查得了井。 - 爆炸半径由树的形状决定,不由代码质量决定。
one_for_one花最少的钱保最大的面;rest_for_one承认启动顺序就是依赖图;one_for_all承认某些组件必须同代。选错策略,要么浪费重启预算,要么让新旧两代状态混在一起——那是最难查的一类故障。 - 错误内核是”重要性”与”工作量”的反比关系。 一个组件越关键,它写的代码就该越少。把复杂逻辑放在树顶,等于把唯一不该崩的东西放在了最容易崩的位置。
- 它迫使状态外置。 重启意味着内存状态归零,所以能做监督的组件必须以”能从外部重建”的方式设计:状态在数据库、在日志、在对端手里。这一约束顺带让组件变成可迁移、可并行、可测试的。
- 它把故障变成可读的证据。 每次崩溃都是一份带原因的 exit reason 和崩溃报告;不让进程死,就没有报告。沉默的降级系统不产生任何证据,因此永远无法被修复。
- Kubernetes 是它的大规模投影。 探针、
restartPolicy、CrashLoopBackOff、控制器之间的父子关系——同一套直觉,只是粒度和代价都大了一到两个数量级。Erlang 的进程重启是微秒级、零调度器参与;容器的重启是秒级、要重拉镜像、要重新挂卷。重启有多便宜,决定了你该多大胆地让它崩。
隐喻对应表
- 一缸一主,谁的缸谁看,旁人不得伸手 → Erlang 进程堆独立、不共享内存,跨进程只能消息传递
- 一个缸翻了,旁边的缸不受影响 → 进程崩溃不会破坏其他进程的状态
- 缸翻了不许捞,掀了重下 → let it crash:不写就地恢复逻辑,终止后从初始状态重启
- 捞洗、补靛、压石灰救回来的”大半” → 半坏状态继续服务,产出与正常结果无法区分
- 看着对、摸着对、只是有一丝酸 → 语义合法但已损坏的状态,最难被下游发现
- 三个月的布褪成花斑,客人才找回来 → 故障延迟暴露,故障点与观测点之间隔着很长的时间与链路
- 半坏的缸比翻了的缸贵 → 带病运行的代价高于一次干净重启
- 墙上木牌刻下日子、缸号、时辰、原因 → crash report:退出原因、时间、调用栈
- “翻一次是意外,翻十次是话” → 单次崩溃是噪声,重复崩溃是系统性缺陷的信号
- 缸主腰间系着绳,绳另一头在院长手上;缸翻绳动 → link 与 exit signal:故障即时上报,不需要轮询巡检
- 院长自己不掀缸,只管谁翻、谁该掀、掀到哪层 → supervisor 只做 start / monitor / restart,不承载业务
- 换一根 →
one_for_one:只重启失败的那个子进程 - 换这一根和它后面的 →
rest_for_one:重启失败者及启动顺序在其后的所有子进程 - 换一院 →
one_for_all:一个失败则全部终止并一同重启 - 开坊照井院→媒染院→染院的顺序点火 → 子进程按 child spec 顺序启动,启动顺序即依赖关系
- 收坊倒着熄火,从上往下,谁都不许自己熄 → 逆序有序关机,由监督者统一发起
- 喊十声没人应,院长才拿锤子敲缸 →
shutdown超时后brutal_kill;敲缸的碎渣会伤到别的缸 → 强制杀死留下未清理的外部资源 - 井院那口井的缸,翻了必下 →
permanent:永远重启 - 季节缸正染着翻了下、收工后翻了不下 →
transient:仅异常退出时重启 - 试色缸从不重下 →
temporary:永不重启 - 一院一个时辰掀三根,就停院 →
max_restarts/max_seconds:重启强度上限 - 停院不解释、不试第四根,系红布上报 → 超限时监督者自身终止,把问题向上移交
- “数字不重要,重要的是它有个数” → 强度阈值可调,但必须存在;无上限的重启等于掩盖
- 三根/一个时辰是七代账本试出来的 → 阈值来自真实故障分布,而非直觉
- 院长一直掀缸,永远查不到井 → 无界重启循环会把永久性缺陷伪装成自愈
- 大掌柜调三天的木牌,发现翻的不止七号 → 上级监督者拥有更大的时间窗与更宽的观测面
- 查出来是墙根裂缝,雨水带土渗进井 → 根因在树的上层,叶子层的所有修复都只是症状处理
- 大掌柜屋里只有一盏灯、一本账、一把井匙 → error kernel:树顶组件应极小、极少依赖、几乎不含业务逻辑
- “我没有缸,我就没有会歪的东西” → 顶层不该持有可失败的业务状态
- “我哪天开始掀缸,就是坊要关了” → 根监督者超限意味着整个应用终止
- 关坊不是塌,是一根一根熄火后锁门 → 有序终止(application stop),不是崩溃
- 院长底下还有灶,灶底下还有柴,各有各的册子 → 监督树是递归的,监督者本身也是被监督的子进程
- 阿绫的晒场只有一张竹架,翻了自己回染院重领 → 叶子节点重启后从上游重新获取状态,不自行重建
- 挑了两个时辰只挑出看得见的黄斑 → 人工筛选只能处理已暴露的损坏,隐性损坏会流向下游
- 阿绫把四十架全掀了 → 承认”无法区分坏与没坏”时,唯一正确动作是整体重置
- “会救的救一匹布,会掀的救一座坊” → 局部恢复保一次请求,结构性重启保整个系统
- 往上走一层就多一口井、多一本账、多一双没缸的手 → 上层监督者拥有更多信息、更大时间窗、更少负载
There was a dye works on the river called Ten Thousand Blues.
It had three courtyards in a row: the well yard, then the mordant yard, then the dye yard. The walls were low, so from a passing boat you could see the rows of vats inside, each with a skin of indigo floating on top, catching the sun like a row of small deep pools.
Ten Thousand Blues had one rule that startled every stranger who heard it.
When a vat turns, you may not fish it out.
A vat of cloth takes three days. On the third morning you open it, and the colour must be as true as a well shaft. If it has gone wrong — grey, green, cloudy, or worst of all, correct to the eye and correct to the hand, but with a thread of sourness when you lean in close — that vat is ruined.
So what do you do with a ruined vat?
Every new apprentice has the same first instinct: fish the cloth out, rinse it in clean water, put in a fresh measure of indigo, press in half a catty of lime to smother the sourness. Three days, forty bolts — surely most of it can be saved.
The old master’s answer was always the same gesture.
He would walk over, look down into the vat once, and then overturn it.
The water went into the ditch. The cloth was dragged out to dry and cut into rags. The vat was scrubbed, refilled from the well, dosed from the indigo cabinet, and started again from the first step of the first day.
Three days. Forty bolts. Into the ditch.
The apprentice would be in too much pain to speak.
The old master said one thing. Ten Thousand Blues passed it down for seven generations:
A half-spoiled vat costs more than a turned one.
—
It took A-Ling three years to understand that sentence.
Her first year, she followed Third Master and watched vats. Third Master spoke very little and taught even less. He taught one thing: when you watch a vat, you do not touch it.
“Watch,” Third Master said. “If it goes wrong, tell me. Don’t stir it. Don’t add water. Don’t patch it.”
A-Ling asked why.
Third Master said: stir it once and it becomes a different thing. It was going to turn. It turns, I know it turned, I start a new vat. You stir it, it doesn’t turn — but it isn’t the same vat either. It will dye a batch that looks excellent, sell, and after three months of wearing fade into patchwork. And when that happens, it won’t be Third Master who comes looking. It will be the whole city.
That year A-Ling recorded thirty-seven turned vats.
Each time, Third Master carved a line into the board on the wall: the day, the vat number, the hour it turned, why it had gone wrong. Only then did he fetch water.
A-Ling asked: why carve that? It’s already turned.
Third Master said: One turn is an accident. Ten turns is a sentence.
—
The spring of her second year, the well yard had a problem.
The water for the mordant yard’s ash liquor was carried up from the well yard. That well had taken two spring rains, and the water had picked up a little iron. Not much — no one could taste it. But ash liquor touched by iron dyes a dull blue.
Vat Seven turned first.
Third Master overturned it and started again.
The next day, Vat Seven turned again.
Third Master overturned it again. On the third morning, Vat Seven turned for the third time.
This time Third Master did not go to the vat. He untied the red cloth from his waist, walked to the mordant yard gate, and tied it to the door ring.
The red cloth went up, and the mordant yard stopped.
A-Ling was frantic: a whole courtyard of cloth is sitting in the vats. What does a stopped day cost?
Third Master said: When one vat turns three times, it is not about the vat.
He said: the first time I thought it was a hand. The second time I thought it was the indigo. The third time I knew I did not understand it. And a thing I do not understand, I can overturn a hundred times and it will still be a hundred times. Overturning vats is what I know how to do. Finding iron in a well is not. So I hand it up.
The red cloth went to the head steward.
The head steward did not overturn a vat, and he did not curse anyone. He did something else: he had the boards from those three days brought to his table and laid them out in a row.
At the ninth board he looked up. More than Vat Seven had turned in those three days. There were Two, Eleven, Fourteen — all of them dyed with liquor from the mordant yard.
So he went to examine the well.
What he found was a crack at the base of the courtyard wall, with rain seeping through the soil into the shaft. They patched the wall, cleaned the well, and the mordant yard reopened.
That afternoon A-Ling stood at the well yard gate and stared at the red cloth for a long time.
She asked Third Master: and if you had overturned it that third time?
Third Master said: then I would have overturned vats until I died. A man who keeps overturning vats never finds the well.
—
Only later did A-Ling learn that the house rules were finer than what she could see.
Well yard, mordant yard, dye yard — that order was not arbitrary. You light the fires in that order to open, and you put them out in reverse to close. Because each courtyard lives off the one before it: no liquor from the mordant yard, no opening the dye yard; no dye yard, nothing to spread in the drying yard.
When a vat turns, how far up you overturn follows the same order.
Sometimes you overturn only that one vat. That is called changing one.
Sometimes a vat in the mordant yard has gone wrong, and then you cannot change only that one — you overturn every vat from that one onward in the opening order. Because all of those used what that vat produced. That is called changing this one and everything after it.
And sometimes, when the colour-head vat of the dye yard goes wrong, the whole dye yard is overturned together. The colour-head sets the year’s colour for the entire yard; if it is wrong, then every “close enough” colour in the other vats stops counting. That is called changing the yard.
Which of the three to use was written on the board beside the vats. It was not allowed to be decided on the spot.
A-Ling asked the head steward: why not just change the yard every time? It’s the safest.
The head steward laughed: three hundred yard-changes a year — are you paying for the cloth?
—
There was something else A-Ling only noticed later.
Not every turned vat gets restarted.
The vat that belongs to the old well is dead: it never rests, and if it turns it is always restarted.
The seasonal indigo vat is alive: if it turns mid-dyeing, restart it; if it turns after the day’s work is finished, leave it and wait for the next season.
The colour-testing vat is once-only: if it turns, it turns. It is never restarted. It existed to be looked at once, and once was enough.
The head steward said: get those three straight and you save half the indigo in a year.
Then there was closing the fires. A yard master never smashes a vat. He calls down and the vat’s keeper scrubs it out and smothers the fire himself. Only after ten calls with no answer does the master break it.
A-Ling asked: why not just smash it? It’s faster.
The head steward said: smash one vat and the whole yard is in splinters. The shards fall into the other vats, and tomorrow you overturn three more.
—
And then there was the rule A-Ling found least reasonable of all.
If a yard overturns three vats within one double-hour, the master must stop the yard.
Not “let’s watch it a while.” Not “let’s hold on a bit longer.” Stop. Red cloth on the door ring. The master stands in the courtyard and waits for the head steward.
A-Ling asked: what if the fourth vat would have been fine?
The head steward said: then it turned for nothing. I accept that.
A-Ling asked: then why three? Why one double-hour?
The head steward said: because those numbers came out of seven generations of ledgers. The numbers themselves don’t matter. What matters is that there is a number.
He said: a master with no number in his head will spend his whole life overturning vats. He will overturn diligently, and painfully, and look like a capable man. And the well that actually broke will never be looked at.
—
In the winter of her third year, A-Ling became a master for the first time.
She had the drying yard. Last courtyard, lightest courtyard. The work was simple: cloth comes up from the dye yard, gets spread on bamboo racks, and you watch the sky and take it in.
Her whole drying yard was one bamboo rack.
The first month, she overturned twice.
The first time, the wind was strong and the rack went over into the mud with the cloth on it. She rolled the cloth up and went back to the dye yard for more.
The second time, she was ill for three days, and when she came back the cloth had dried past its time and was stiff enough to stand on end. She rolled it up and went back to the dye yard for more.
Both times she did the right thing.
The third month, it happened.
It snowed for half a month without stopping. The drying yard took in forty racks of cloth and stacked them indoors. There was a charcoal brazier in the room, and the fumes sat and did not clear, and a little yellow spotting appeared on the cloth.
A-Ling’s first instinct was to pick out the spotted pieces, hang them alone in the draught, and see whether it would blow off.
She crouched by the pile and picked for two double-hours.
At the thirty-seventh piece, her hands stopped.
She remembered what Third Master had said: stir it once and it becomes a different thing.
She stood up, entered all forty racks into the ledger one by one, and went to knock on the head steward’s door.
She said: I overturned the drying yard.
The head steward was eating congee. He looked up: all of it?
A-Ling said: all of it. The spotting is not something I can pick clean. I picked for two double-hours, and everything I picked out was the part I could see. The part I couldn’t see will grow in the customer’s wardrobe.
The head steward put down the bowl and looked at her for a long time.
Then he said: come to my room tonight. I’ll show you the ledger.
—
That night, the head steward opened a very old book.
In it was drawn a tree. But it didn’t look like a tree — it looked like an upside-down dye works: a bar at the bottom, three forks rising from it, and from each fork a few more lines.
The head steward said: this is the root of Ten Thousand Blues.
The bar at the bottom was him. The three forks above it were the three yard masters. Above each master were the vats of that yard. And if something stood above a vat — say the stove that tended the fire in the dye yard — then the stove had its own little book, drawing the sticks of firewood that stood above it.
A-Ling said: and me?
The head steward pointed to a line at the very edge: you are here. Above you is the drying yard. If the drying yard turns, I know. If the drying yard can’t hold, I know and I have to move. And if I can’t hold—
He paused.
If I can’t hold, the works closes.
A-Ling asked: what does closing look like?
The head steward said: closing is not a collapse. Closing is me putting out the fires one by one, from the top down, and nobody is allowed to put out his own. When the last stove is out, I lock the door.
He said: in this seat, I don’t overturn two vats in a year. The day I start overturning vats is the day the works is closing.
A-Ling asked: why can’t you overturn any?
The head steward said: because I am not supposed to have a vat.
He said: look at what’s in this room. One lamp, one ledger, one well key. I have no vat, so I have nothing that can go wrong. The only work I have is: who turned, who should be overturned, and how far up. That work looks light. It is the heaviest work here — which is why nothing else is allowed on top of it.
—
A-Ling grew old in time.
Someone asked her: why has Ten Thousand Blues stood for a hundred years?
She said: because it is not afraid of turned vats.
The questioner said: which dye works is afraid of turned vats?
A-Ling said: plenty of them are not afraid of turning a vat. What makes Ten Thousand Blues different is — it is not afraid of failing to save itself.
She said: one vat is ruined, I overturn it and start again. One vat turns three times running, the master stops the yard. One yard stops three times, I stop the works. I never know what the next turned vat will cost. All I know is that every turn goes up one level. And the level above has something the level below doesn’t — another well, another ledger, another pair of hands with no vat of their own.
So the problem always gets handed, while it is still small, to someone who can see it.
The last thing A-Ling said was carved on the well yard wall:
The one who saves, saves a bolt. The one who overturns, saves a works.
— —
By now you’ve probably recognized it: this is the Erlang/OTP supervision tree — the architecture behind the doctrine called let it crash.
What it is
Erlang’s unit of concurrency is the process: extremely light, single-threaded, with its own heap and no shared memory. Two processes hold no pointers into each other. They exchange messages. This gives rise to one consequence, and that consequence is the foundation of the whole fault-tolerance model:
One process crashing cannot corrupt another process’s data.
So Erlang’s idiom runs against the mainstream. The mainstream anticipates every failure inside every function, catches it at each layer, repairs the bad state in place. Erlang’s slogan is let it crash — do not write recovery logic into business code; let the process die cleanly and restart from a known-good initial state. The reasoning: a process that is half-broken but still running keeps producing answers that look correct, and those answers cannot be distinguished from correct ones. A dead process is at least honest.
A link ties two processes’ fates together: when one exits abnormally, the other receives an exit signal. A monitor is the one-way version — notification without shared fate.
A supervisor is a process that does three things: start its children in order, watch them exit, restart them according to a strategy. It does no work itself. Each child is described by a child spec: how to start it, its restart type, its shutdown timeout.
There are three restart strategies, and they map to real dependency structure:
one_for_one: restart only the child that died.rest_for_one: restart the dead child and every child started after it — because they depended on it.one_for_all: one dies, all are killed and restarted together — because they must share a generation.
Restart types come in three flavours: permanent (always restarted), transient (restarted only on abnormal exit), temporary (never restarted).
Restart intensity is the safety valve: each supervisor carries max_restarts and max_seconds. If restarts exceed the limit inside the window, the supervisor stops restarting and terminates itself, handing the problem to its own supervisor. That supervisor has a wider window, a wider view, and less work in flight. If the root supervisor exceeds its limit, the entire application terminates.
The error kernel is the design principle that follows: the closer a component is to the top of the tree, the less it should do. The top holds only a little very stable logic that should never restart — configuration, the name registry, connection-pool bookkeeping — and pushes everything risky, crashy, and complicated down to the leaves. The cost of a crash is thereby bounded to the lower tree, while the top retains enough context to answer “is this actually a problem with the well?”
Around all of this: ordered startup, reverse-order shutdown; shutdown sends shutdown and waits for a timeout before resorting to brutal_kill; registered names let clients find a service by name after a restart instead of chasing a pid; and every crash emits a crash report with the full exit reason and stack trace.
Why it matters
- It turns fault tolerance from prediction into structure. Conventional code asks you to anticipate failure modes and write a recovery branch for each, and failure modes are unbounded. The supervision tree admits it cannot predict: shrink the fault domain, make crashing cheap, make restarting fast. The “nine nines” (99.9999999%) availability figure in the Erlang world does not come from smarter recovery logic. It comes from the arithmetic of “it crashed, so restart it.”
- Restart intensity bounds how far a failure travels. An auto-restart system without
max_restartsspirals: a permanent defect is buried under infinite retries, and the system looks like it is healing while it is idling. When the limit is exceeded, the supervisor terminating itself is not surrender — it is handing the decision to the layer that has more information. A leaf can only overturn vats. The top of the tree is what can examine the well. - Blast radius is set by the shape of the tree, not by code quality.
one_for_onespends the least to protect the most.rest_for_oneadmits that startup order is the dependency graph.one_for_alladmits that some components must share a generation. Pick the wrong strategy and you either waste your restart budget or mix two generations of state together — the hardest class of failure to diagnose. - The error kernel is an inverse relation between importance and workload. The more critical a component is, the less code it should contain. Putting complex logic at the top of the tree puts the one thing that must not fail in the place most likely to fail.
- It forces state out of the process. A restart zeroes memory, so any supervised component must be designed to be rebuilt from outside: state in a database, in a log, in the peer’s hands. That constraint incidentally makes components movable, parallelizable, and testable.
- It converts failure into readable evidence. Every crash is an exit reason plus a crash report. Do not let the process die and you get no report. A silently degrading system produces no evidence at all, and therefore can never be fixed.
- Kubernetes is its large-scale projection. Probes,
restartPolicy,CrashLoopBackOff, the parent-child relation between controllers — the same intuitions, with granularity and cost one or two orders of magnitude larger. An Erlang process restart costs microseconds with no scheduler involvement; a container restart costs seconds, an image pull, and a volume reattach. How cheap your restart is decides how boldly you are allowed to crash.
Metaphor mapping
- One vat, one keeper; nobody else puts a hand in → independent per-process heaps, no shared memory; cross-process communication is by message only
- A turned vat leaves the neighbouring vats untouched → a process crash cannot corrupt another process’s state
- Do not fish out a turned vat; overturn and restart → let it crash: no in-place recovery logic; terminate and restart from initial state
- Rinsing, re-dosing, lime to smother the sourness → half-broken state kept in service, producing output indistinguishable from correct
- Correct to the eye, correct to the hand, one thread of sourness → syntactically valid but corrupted state, hardest for downstream to detect
- The cloth fades into patchwork after three months and only then does the customer return → delayed failure exposure; the fault point and the observation point are far apart in time
- A half-spoiled vat costs more than a turned one → degraded operation costs more than one clean restart
- Carving day, vat number, hour, and reason into the board → crash reports: exit reason, timestamp, stack trace
- “One turn is an accident, ten turns is a sentence” → a single crash is noise; repeated crashes are a signal about a systematic defect
- A cord from each keeper’s waist to the master’s hand; a turned vat jerks it → links and exit signals; failure is reported immediately, with no polling rounds
- The master does not overturn vats; he decides who turned, who gets overturned, how far up → supervisors only start, monitor, and restart; they carry no business logic
- Changing one →
one_for_one - Changing this one and everything after it →
rest_for_one - Changing the yard →
one_for_all - Lighting the fires in well yard → mordant yard → dye yard order → children start in child-spec order; startup order is the dependency graph
- Closing the fires in reverse, from the top, nobody allowed to close his own → ordered graceful shutdown initiated by the supervisor
- Ten calls unanswered before the master breaks the vat →
shutdowntimeout thenbrutal_kill; the shards that injure other vats stand for external resources left uncleaned by a hard kill - The well’s vat, dead, restarted whenever it turns →
permanent - The seasonal vat, restarted mid-dye but not after hours →
transient: restarted only on abnormal exit - The colour-testing vat, never restarted →
temporary - Three vats in one double-hour stops the yard →
max_restarts/max_seconds, the restart intensity limit - The yard stops without argument, without trying a fourth, and the red cloth goes up → on exceeding the limit the supervisor terminates itself and escalates
- “The numbers don’t matter; what matters is that there is a number” → intensity thresholds are tunable but must exist; unbounded restart is concealment
- Three and one double-hour came out of seven generations of ledgers → thresholds come from real failure distributions, not intuition
- A master who keeps overturning vats never finds the well → an unbounded restart loop disguises a permanent defect as self-healing
- The head steward compares three days of boards and finds more than Vat Seven → the supervising layer holds a wider time window and a wider observation surface
- The cause is a crack at the wall base letting rain into the well → the root cause is above the leaf level; every leaf-level repair was symptom handling
- The head steward’s room holds one lamp, one ledger, one well key → the error kernel: top-of-tree components must be tiny, dependency-light, almost free of business logic
- “I have no vat, so I have nothing that can go wrong” → the top layer must not hold fallible business state
- “The day I start overturning vats is the day the works is closing” → the root supervisor exceeding its limit means the whole application terminates
- Closing is not a collapse; it is fires put out one by one, then the door locked → ordered application stop, not a crash
- Below each master are stoves; below each stove, firewood; each with its own book → the supervision tree is recursive; supervisors are themselves supervised children
- A-Ling’s drying yard is one bamboo rack; she goes back to the dye yard for more → restarted leaves re-acquire state from upstream rather than rebuilding it themselves
- Two double-hours of picking, and only the visible spotting comes out → manual filtering can only handle exposed damage; latent damage flows downstream
- A-Ling overturns all forty racks → when you cannot distinguish damaged from undamaged, a full reset is the only correct action
- “The one who saves saves a bolt; the one who overturns saves a works” → local recovery preserves one request; structural restart preserves the system
- Every level up brings another well, another ledger, another pair of hands with no vat → higher supervisors have more information, a wider window, and less load