第 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 为内容指纹与审计锚 |
本章涉及的 API 参考
xrt 延伸阅读
- xrt 参考 · queue — 意图队列与结果环底层的 SPSC/MPSC 结构