配置发布模型应该如何设计?
简化版
配置发布模型应把草稿内容、不可变版本、目标作用域和发布记录分开。 编辑不直接影响运行实例;通过校验和审批后生成不可变版本,再由发布状态机灰度、扩量、暂停、完成或回滚。 客户端读取本实例的当前期望版本,校验后原子应用并上报实际版本。
详细版
候选版本绑定 baseVersion,防止并发覆盖。 发布记录包含 changeId、内容版本、环境/租户/命名空间、灰度规则、创建人、审批、门禁、时间和回滚来源。 已发布内容不可修改,回滚是创建新发布记录而非删除历史。
状态机可为 CREATED、VALIDATED、APPROVED、CANARY、EXPANDING、COMPLETED、PAUSED、ROLLED_BACK、FAILED。 每次迁移使用幂等命令与乐观锁,控制器重启后能从持久状态继续。 通知只加速发现,客户端定期读取当前期望状态补漏。
完整版教学
一、为什么要分离编辑和发布
若控制台保存就直接影响生产,误触和半成品会立即扩散。 草稿允许反复编辑;候选版本用于校验审批;不可变版本才可进入发布。 分离后才能准确回答谁批准了哪份内容并发布给谁。
发布的基本单位应是“不可变内容 + 明确作用域 + 可审计决策”。
二、核心实体
| 实体 | 作用 |
|---|---|
| Draft | 可编辑工作区 |
| ConfigVersion | 不可变内容与摘要 |
| Release | 内容到作用域的发布决策 |
| Assignment | 某目标当前期望版本 |
| ClientStatus | 客户端实际应用状态 |
内容与发布分离后,同一内容可用于灰度、全量和回滚,而不复制模糊记录。
三、并发控制
提交候选时携带 baseVersion。 若当前版本已变化,则拒绝提交并要求重新生成 diff。
if currentVersion != baseVersion:
reject(CONFLICT)
else:
create immutable candidate
这防止后提交者无意覆盖先发布者的修改。
四、发布状态机
状态迁移必须有明确前置条件。 APPROVED 才能进入 CANARY,灰度收敛和指标达标才进入 EXPANDING。 门禁失败进入 PAUSED,由预案决定继续、修正或回滚。 COMPLETED 也不能删除,后续回滚引用其历史内容。
CREATED -> VALIDATED -> APPROVED -> CANARY
-> EXPANDING -> COMPLETED
\-> PAUSED -> ROLLED_BACK
五、幂等与故障恢复
发布命令携带 changeId 和期望状态版本。 重试同一命令不能创建重复发布;并发状态迁移用乐观锁只允许一个成功。 控制器状态持久化,重启后扫描未终态任务继续执行。 外部通知使用 outbox 等方式避免数据库提交后事件永久丢失。
六、客户端视角
客户端查询“我当前应该使用哪个版本”,不自行拼接发布历史。 下载完整内容后核对身份、摘要、schema 和业务约束,再原子交换。 应用失败保留旧值并上报失败原因。 通知丢失时周期校准仍能发现期望版本变化。
七、灰度、回滚和审计
发布记录保存灰度规则快照、每阶段门禁和目标集合。 回滚创建更高的新发布序列,内容引用历史版本,避免版本倒退和审计断裂。 审计串联草稿、差异、校验、审批、状态迁移、客户端收敛和操作者。 敏感值不写入普通审计正文,只记录 secretRef 与版本。
八、常见误区与追问
- 误区:保存配置就是发布配置。 编辑态与运行态必须分开。
- 误区:发布只需要 content 和时间。 还要作用域、审批、规则、门禁和状态。
- 误区:失败后删除发布记录最干净。 历史必须不可变,回滚是新决策。
- 误区:发出通知即可标记完成。 应以目标客户端收敛和业务门禁判断。
- 追问:控制器重启怎么办? 从持久状态恢复,并用幂等命令继续。
- 追问:并发发布如何防覆盖? baseVersion、乐观锁和作用域冲突检测。
- 追问:通知丢失怎么办? 客户端周期读取当前期望版本做反熵。
九、加强记忆
- 草稿、内容版本、发布与客户端状态分离。
- 候选绑定基线,已发布内容不可变。
- 用持久化状态机驱动灰度与扩量。
- 每个命令幂等,失败可恢复。
- 完成以实际收敛和业务指标为准,回滚仍是一条新发布。