第21章|发布策略 2:回滚、前滚与紧急修复(hotfix)

发布体系真正的“成人礼”不是你能发多快,而是你能多快、又多稳地恢复。 回滚不是按钮,回滚是一个系统:回滚对象数据兼容权限与审计, 以及当回滚不可行时,如何用 前滚(rollforward) 把问题“修好并继续向前”。

First principle

回滚的对象是 bundle

  • 回滚必须回到“上一套已知好组合”
  • app_digest + config_version + flags_snapshot
  • 只回滚镜像不回滚配置,等于把事故续命
Hard truth

数据经常决定“能不能回滚”

  • schema 已推进且不兼容:回滚可能更危险
  • 用 expand/contract 把“回滚窗口”做出来
  • 必要时选择前滚:快速修复 + 再次发布
Hotfix

紧急通道必须可控、可审计

  • 更少步骤,不代表更少治理
  • 权限更严格:最小授权 + 双人原则
  • 必须带证据链:谁、何时、为什么、改了什么

1. Rollback vs Rollforward:别把“撤退”当成唯一解

当线上出事,你通常有两条路:

什么时候更偏向前滚?
- 已经做了不可逆的数据变更(或回滚会引入更大一致性风险)
- 安全漏洞需要“修复并补洞”,而不是退回到旧漏洞
- 回滚成本太高(需要长时间停机)而前滚可以快速止血

2. 回滚决策树:先止血,再归因,再选择策略

事故现场最怕“讨论哲学”。你需要一个决策树把团队从混乱拉回到可执行的步骤。

回滚决策树:把“慌”变成“步骤” 先止血(降低爆炸半径)→ 再选择回滚/前滚 → 最后补齐治理与复盘 0) 先止血:降低爆炸半径 freeze rollout · kill switch · traffic cap · disable feature 1) 能否安全回滚? 数据/协议/缓存 是否向后兼容? 是否存在不可逆迁移或破坏性变更? 2) 选择策略(回滚 or 前滚) 回滚:回到上一套 bundle(known-good) 前滚:快速修复 → 重新发布(更安全时) Rollback path bundle rollback · verify · resume cautiously Rollforward path hotfix · limited rollout · verify · expand 最后:补齐复盘与治理(门禁、兼容策略、演练、监控阈值)
图 1:回滚决策树。先止血(冻结发布/开关止损),再根据数据与兼容性选择回滚或前滚。

3. 数据决定一切:Expand/Contract 给你“可回滚窗口”

只要涉及数据库或持久化状态,回滚就会变得困难:新版本写入的新字段、改变的数据语义、迁移后的索引与约束,都会让旧版本无法读取或产生错误逻辑。 所以成熟团队会把数据变更拆成两个阶段:

  1. Expand:只做向后兼容的扩展(加字段、加表、双写、加索引但不移除旧能力)。
  2. Contract:在旧版本不再需要时再清理(删字段、删表、移除旧代码路径)。
要点:Expand 阶段是你的“回滚保险丝”。只要还没进入 Contract,你通常还能安全回滚(因为旧版本仍然能读写旧路径)。
数据迁移时间线:Expand/Contract 目标:把回滚从“可能不行”变成“设计出来的窗口” time Expand (compatible) add field/table · dual write · backfill old code still works Contract (breaking cleanup) remove old paths · drop field/table rollback becomes risky deploy v1 deploy v2 start contract cleanup done rollback window risky rollback zone Practical pattern 先发布支持新旧 schema 的代码 → 再迁移数据 → 最后删旧路径(contract)并且只在稳定窗口执行
图 2:Expand/Contract 时间线。Expand 阶段设计“可回滚窗口”,Contract 阶段再做破坏性清理。

4. Hotfix 通道:更少步骤,但更强控制

hotfix 的目标是“快速止损”,但它常常把团队带入另一个坑:为了快,把治理全删了,结果是更快地引入第二个事故。 正确的 hotfix 通道应该是:步骤更少,但控制更强。

4.1 hotfix 的最小流程(建议落地成模板)

  1. 触发条件:明确什么算“紧急”(SLO 破坏、核心路径不可用、安全漏洞)。
  2. 权限模型:最小授权 + 双人原则(至少两人审批或两人密钥)。
  3. 变更范围:只允许最小修复,禁止“顺手重构”。
  4. 验证策略:最小必要测试集 + 关键回归(别全跑,但也别裸奔)。
  5. 发布策略:优先小比例金丝雀 + 强止损;或直接回滚 bundle 先止血。
  6. 审计证据链:issue/工单、审批记录、制品 digest、发布标记、影响范围。
Hotfix 通道:快,但不乱(控制更强、证据更全) 目标:最小变更 + 最小必要验证 + 强审计 + 强止损 Normal release lane Hotfix lane CI full · scans · approvals · canary · expand Hotfix lane (controlled) short path, stronger controls Control 2-person approval · least privilege Verify minimal tests · key regressions Mitigate canary + kill switch + audit Audit chain: ticket → approver → artifact digest → release marker → impact scope
图 3:hotfix 通道不是“删步骤”,而是“缩路径 + 加控制”。它必须更可审计、更可止损。

5. 最小落地清单(把“能救火”变成“可持续救火”)

  1. 预置回滚:上一套 bundle 永远可用;回滚演练常态化。
  2. 数据兼容策略:默认向后兼容;迁移用 expand/contract 拆阶段。
  3. 止损能力:kill switch、冻结发布、限流、降级必须可一键执行。
  4. hotfix 治理:双人原则、最小权限、最小变更、审计链路完整。
  5. 复盘闭环:把这次事故的“触发条件、缺失门禁、误判指标”变成规则与自动化。
你现在应该能回答:
1) 我们回滚时回滚的对象是什么?是否能回到上一套已知好组合?
2) 当前数据变更是否允许回滚?如果不允许,我们的前滚策略是什么?
3) hotfix 通道是否做到“更快但更可控”?证据链是否完整?
← 上一章:发布策略 1 下一章:数据库变更与交付(迁移、兼容、零停机) →