CORDISDSH 的心脏第 07 章 · 思想四 · 一生全书目录术语表读论文原文 ↗
第七章 · 思想四 · 动态组装演算

乱按也不怕:
一个组件的一生

前三章讲的是零件,这一章讲整机。论文用 26 页公式证明:一大群组件同时装装卸卸,系统也不会乱。你不用看公式,看它定下的几条规矩就够了。

约 8 分钟 · 上一章 06 思想三 · 一扇门 · 下一章 08 思想五 · 落地

题图插上,拔下,再插上。

从零件到整机

论文把前三个思想合成一个东西,叫组件。一个组件说清三件事:我需要什么(反效应),我提供什么,我上岗以后做什么(效应)。说白了是一份岗位说明书。

说明书本身不干活。真正上岗的,是它的一次具体实例,论文叫 fiber。打个比方:说明书是「前台」这个职位,fiber 是某天入职的那个人,随身带着自己的回执串。同一份说明书可以同时有好几个人在岗,各管各的。

人只下三道命令

整个系统里,人(或者配置文件)能下的命令只有三道:插入一个组件、让它退役、把它移除。

其余的事全按规则自动流转。一个 fiber 一生会经过这几个阶段:

阶段 意思 什么时候进入
空闲 在名册上,没上岗 刚插入,或依赖还不齐
激活中 正在一件件做它的效应、收回执 需求清单从缺到齐
在岗 正常工作 效应全部做完
停用中 正在倒着撕回执 退役,或依赖从齐到缺
失败 停下了,原因写明 激活到一半出错

你从来不用手动说「现在激活它」「现在停用它」。你只说想要什么,什么时候上岗、什么时候歇着,由需求清单和环境的变化决定。

走的时候,为什么不会卡死

最容易出事的是「走」。数据库要停用,可提醒插件还在用它,怎么办?

规矩是:有人还在用你,你就不能先走。这类护栏通常会死锁:两边互相等,谁也走不了 p.37。Cordis 的解法分两步:

  1. 要走的那位,先挂出停工告示:把自己从「可供货」的名单上撤下来。从这一刻起,没有新的组件能再依赖它。
  2. 已经依赖它的组件,发现供货的要走,就按依赖关系一个个停用,各自撕干净回执。

新的依赖进不来,旧的依赖都在退场,护栏就一定会放行。论文把这条证成了「进展」:系统不会卡在半路。还有一条配套规矩:同一个名字,同一时刻最多一个供货的。不会出现两个数据库同时自称是「数据库」,下游不知道该听谁的。

乱按也不怕

演示 7.1 · 可以点,最后可以随便按乱按也不怕
    配置 · 你想要的
    系统 · 实际在跑的
    数据库未装
    提醒未装
    统计未装
    天气未装
    网页面板未装
    旁白左边是配置:你只说想要哪些组件。右边是系统的真实状态,由运行时按依赖自己安排。按「开始」,先把五个都勾上。
    引导播完后,左边的开关可以随便按

    演示最后那一拍,是这一章最重要的结论,论文叫汇聚:不管一个系统中途经历过怎样的装装卸卸,它停下来时的状态,都等于把最后在岗的那些组件按依赖顺序各装一次、从未卸载过 p.51。

    换句话说,过程不留痕迹。中途装过又拆掉的组件、反复断开的依赖,不会在系统里留下任何「历史」。这也是为什么前面几章的保证可以放心叠在一起用。

    还有一种结局要说清:如果一个组件激活到一半失败了,它停在「失败」,原因写明,已经做成的部分按回执撤掉;环境没变,就不会反复重试。它不会把错误传染给邻居:和成功的结局相比,只差这一个组件的状态 p.55。

    热重载与声明式配置

    有了上面这些,两个实用功能几乎是白送的。

    图 7.1 · 原地换一块

    热重载:拆旧装新,失败整体回滚

    改了源码,不用重启。热重载的做法就是拆掉旧 fiber、用新代码装一个新的 p.67。

    而且它是事务式的:哪怕一个模块因为语法错误导入失败,所有改动整体回滚到备份,系统永远不会停在「换了一半」p.68。代价是新 fiber 从头装起,组件自己内存里攒的东西不保留。

    声明式配置更进一步:整个系统写成一份配置,你只写「应该是什么样」,加载器负责把现实改成那样,而且一直保持同步 p.65。你改一行配置,加载器只动有差别的那几个组件。这就是演示里左边那排开关在做的事。

    带走这一句

    人只说想要什么;谁先上岗、谁先离场、半路失败怎么收尾,交给规则。

    请为这个项目设计一个声明式的模块加载器:
    1. 用一份配置列出想启用的模块,模块各自声明依赖;
    2. 加载器根据配置和依赖,计算每个模块应处于「运行」「等待依赖」还是「未启用」;
    3. 配置变化时,只处理有差别的模块:先按依赖倒序停止,再按依赖正序启动;
    4. 模块启动失败时,只撤销它已完成的部分,标记为失败并记录原因,不影响其他模块;
    5. 写一个测试:随机开关模块 100 次后,系统状态应与「按最终配置从零启动」完全一致。