第 26 章 / 共 51 章
卷四 · 热重载深潜

重载模型:期望状态协调

热重载不是一个函数,而是一个协调系统。本章建立它的心智模型——理解了"意图"与"快照",后面五章都是在这个模型上加细节。

本章导读

站位:卷四的地图章。第 3 章埋的"代"、第 13 章的拒绝清单,在本章合成完整模型;ch27-31 分别展开触发、交接、代际、GC、反模式。

26.1 引入

朴素的热重载设计是"调用一个函数,同步换掉代码"——它在并发世界里立刻破产:调用时还有 50 个请求在旧代码上跑,换什么?怎么换?XServer 的答案是把它建模为期望状态协调(desired-state reconciliation):你提交的不是"现在就换",而是"我希望服务变成这份内容";协调器(独立的 reload 控制线程)串行地比较、编译、发布,并把结果记录成可查询的终态。这个模型天然解决了并发、失败、重复提交三类问题。

26.2 期望状态协调

你(任意 worker 线程) reload 控制线程(串行) ──────────────────── ────────────────────── xsReloadHostSubmit(pHost) │ 立即返回稳定 ID(非阻塞) ▼ ┌─ 受理(进 pending 队列 ≤64) xsdReloadQuery(id, &result) ◀── 终态 ──┤ 冻结不可变快照(配置+源码 → Revision) State / Revision / Message │ 全量候选预编译 ──失败──▶ FAILED(旧代原样) │ 原子发布(新代上线) └─ SUCCEEDED
  • 提交与执行解耦:Submit 永不阻塞调用线程——你在请求回调里就能提交重载
  • 单线程协调:所有意图在一条控制线程上串行执行——没有"两个重载互相踩"的并发问题
  • 结果可审计:每个意图有稳定 ID 与七态终态,环形结果表存最近 256 条

26.3 意图与七态

一次 Submit 就是一个意图(intent)。意图的生命周期:

ACCEPTED ──▶ PREPARING ──▶ SUCCEEDED /* 成功发布 */ │ ├──▶ FAILED /* 编译/校验失败,旧代原样服务 */ │ ├──▶ SUPERSEDED /* 被同 server 更新意图覆盖 */ └──▶ CANCELLED /* 进入副作用区前被取消 */ latest-wins 合并:同 server 新意图覆盖未执行的旧意图 (防止过期配置排队执行);pending 上限 64、结果环 256

latest-wins 是个容易被低估的设计:连续改五次配置再提交五次,只有最后一份会执行——中间态从未上线。这对"边想边改"的开发流和"快速回滚"的运维流都恰好是对的语义。

26.4 不可变快照

受理意图时,协调器做一件关键的事:冻结输入——配置字节 + 全部相关脚本源码在那一刻被快照,并算出内容指纹(Revision)。此后:

  • 一次 reconcile(尤其 xsReloadAllSubmit)里所有 server 看到同一份输入——不存在"A 服务用了新配置、B 服务用了半新配置"的撕裂
  • 执行期间磁盘上的文件再怎么变,都不影响这次意图——改文件与提交意图是两个动作,快照之后才算一个完整事务
  • Revision 是审计锚点:两次成功重载 Revision 相同 = 内容没变(协调器可据此短路);运维日志记下 Revision 序列即可追溯"哪个版本上过线"

26.5 契约

  • 提交线:Submit 非阻塞、返回稳定 ID;0 = 未受理(如 pending 满)。
  • 执行线:单控制线程串行;副作用区(发布)之后新意图只能排队不能取消在途者。
  • 输入线:意图冻结不可变快照;Revision 是内容指纹与审计锚。

常见错误

把 Submit 当同步命令
症状
Submit 后立刻断言新行为,测试随机失败。
原因
Submit 只表示"意图已受理"——终态要 Query。bool 包装(xsReloadHost 等)也只表示受理成功。
✗ 错误
xsReloadHost(pHost);
assert(NewBehavior());  /* 未必已发布 */
✓ 正确
XS_ReloadId id = xsReloadHostSubmit(pHost);
/* 轮询 xsReloadQuery 到终态再断言 */
改了文件以为会自动重载
症状
编辑 devfile 后服务行为不变。
原因
XServer 没有内置文件监听——改文件只是改文件;快照发生在提交意图时。想要"保存即重载"的开发体验,用 xrt 文件监听 + 自动 Submit 自建(ch27 练习)。

编程练习

基础意图生命周期观察

写管理路由提交重载并每 10ms Query 一次,打印 State 变化序列。

验收:成功路径能看到 ACCEPTED→(PREPARING)→SUCCEEDED;故意提交坏脚本看到 FAILED。
进阶latest-wins 实证

快速连发三个意图(每版路由返回不同标记),确认只有最后版上线、前两个 SUPERSEDED。

验收:三个 ID 都能查到终态;服务行为等于第三版。
挑战Revision 审计日志

给管理路由加历史查询:按结果环输出最近 N 次意图的 ID/State/Revision/Message。

验收:能对上"哪次提交对应现在跑的版本";重复提交未改内容时 Revision 不变。

小结

要点结论
模型期望状态协调:提交意图,非同步命令
执行单控制线程串行;Submit 非阻塞返回稳定 ID
七态ACCEPTED→PREPARING→SUCCEEDED/FAILED/SUPERSEDED/CANCELLED
latest-wins同 server 旧意图被覆盖;中间态不上线
快照受理即冻结输入;Revision 为内容指纹与审计锚
xrt 延伸阅读