有状态编排的隐藏成本

SchemaBridge Team · 2026-02-02 · Distributed Systems, Immutable Infrastructure, Orchestration, Anti-Patterns, Reliability

为什么你那些“简单”的内部工具可能是你最大的可靠性风险,以及如何通过将不可变基础设施(Immutable Infrastructure)模式应用到应用逻辑中来化解它。

在微服务的世界里,我们痴迷于解耦。我们使用队列,采用事件驱动架构,拆分单体应用。然而,在我们的编排引擎内部,我们却常常犯下分布式系统中的大忌:我们编写有状态的循环。

在 SchemaBridge,我们最近对核心系统工作流进行了全面改造。在这个过程中,我们发现自己正面对着困扰许多工程组织的同一批反模式。这不仅仅是关于我们发布说明的故事,更是一次将不可变基础设施原则应用于应用层的案例研究。

“循环”反模式

考虑一下经典的“轮询器”:

while not deployment.is_ready():
    sleep(60)
    check_status()

这段代码假设了一个稳定不变的宇宙。它假设轮询进程会永远存活下去。而现实中,这正是分布式单体的产物。正如 [AWS Builders' Library] 所指出的,依赖长时间运行的同步状态会产生“僵尸”进程和不可预测的故障模式。

解决方案:递归链式调用

我们将内部的 while 循环替换为递归执行模型,这与函数式编程中使用的延续传递风格(Continuation Passing Style),或分布式事务中的Saga 模式十分相似。

不可变逻辑:使用“内容寻址”身份进行版本控制

版本控制素来是个难题。当你更新一个工作流定义时,那些可能已经在运行的执行实例会发生什么?

我们实现了规范化 DSL 哈希

通过对我们工作流逻辑的抽象语法树(AST)进行哈希处理,我们将每个版本都视为一个唯一的、内容寻址的实体。这与 temporal.io 等现代引擎所采用的策略一致:执行身份与代码身份绑定

锁定“上帝模式”

最后,我们解决了内部工具的安全性问题。让内部“清理”脚本拥有 root 权限是很常见的做法。这违反了最小权限原则

我们发现,我们自己内部的“渐进式发布”工具竟然有能力覆盖关键的系统 ID。我们通过一种“Sudo”模式对此进行了锁定,只有经过密码学验证的系统参与者才能请求特定的逻辑 ID。

结论

如果你的编排依赖于 sleep(),你就是在与云对抗。

通过拥抱递归不可变性严格身份,我们从“基于希望”的编排走向了“基于证明”的编排。

延伸阅读:

深入了解