发布与回滚
回滚只切回上一版程序,规则等带版本的数据留在库里不动
上线出问题,回滚只切回上一版程序,数据库保持不动;这要求每份库结构变更都只加不改,让上一版程序在新的库结构上照常运行。规则、权限、口径是带版本的数据,存在库里,回滚时库不动;模型每次调用用了哪一版投影,都记在留痕里。新版本一旦写入了旧版本读不懂的数据,比如新的状态值,就不能直接回代码;需要把流量分批切给新版本的多实例部署,也不适合这套做法。
回滚成立的前提
「回滚就是把指针切回上一版,库不动」只在下面的前提同时成立时对。
| 前提 | 为什么需要 | 破了怎么办 |
|---|---|---|
| 库结构变更只加不改:新表、可空的新列、旧名转发壳、保留的旧函数 | 上一版程序只读旧结构;旧结构还在、没被改过,它就照常运行 | 库结构变更改动了旧结构,上一版程序在新库上可能报错,不能直接回代码 |
| 新版本没有写入旧版本不理解的数据 | 旧程序读到新状态值会出错 | 每份结构变更脚本的文件头写「回滚前置检查」,例如新状态已出现时不能直接回程序,只能前滚 |
连库一起回退,只在库内还没有新数据时才做。
核对回滚方案,先看这些前提在每份结构变更脚本上怎样检查,而不是只看「能切指针」。
先扩后缩
图里蓝色的是回滚一步:指针回到旧程序,库保持新结构,旧程序照常运行。
这是通用的 expand / contract 做法,也叫 Parallel Change。先扩:在旧结构旁加上新结构,新旧并存。再把使用者切到新结构。最后缩:没有人再用旧结构时才删它。SZV 的只加不改的变更对应第一步。删旧结构那一步,要等没有任何版本再读它之后才做。
库结构变更的写法
| 纪律 | 内容 |
|---|---|
| 清单按依赖序排 | 先后顺序来自依赖关系,不来自文件名 |
| 执行计划是清单与台账的差集 | 清单里有、台账里没有的才执行,不认「台账尾」,拒绝整批重放 |
| 全部幂等 | 同一个文件执行两遍,结果相同:IF NOT EXISTS、ON CONFLICT DO NOTHING、CREATE OR REPLACE |
| 克隆库彩排两遍 | 第二遍必须零变动 |
| 每个文件一个顶层事务 | 末段带行为级自检,不符,整个文件撤销 |
| 带强锁的结构变更放进停顿窗口 | 并设锁等待上限 |
| 文件头写明回滚步骤与回滚前置检查 | 不必临时去查 |
| 数据步与结构变更分开 | 换码之后的数据步,如会话版本号,放在独立目录,随生产变更的书面执行令(见下文)一起走 |
事务指文件里的语句要么全部生效,要么全部撤销。幂等指重复执行不改变结果。
结构变更脚本是否可以安全重放、能不能回滚,看文件头与彩排结果就能判断。
发布物
每个版本一个独立的发布目录,建好之后不再改。两个指针:当前版本、上一版本。切换是原子换指针,一步完成,停顿很短,不撤销已登录的会话。清理旧目录时,不得删除上一版本。
上线前,先在非生产环境重放结构变更脚本两遍并做业务验证,再上生产。非生产环境的库用脱敏后的数据,个人信息表只留结构。
生产变更的书面执行令
生产变更须有书面执行令,令中写明目标版本、校验和、回滚点与备份锚。同一时刻只允许有一次生产变更在执行。
一次上线按下面的顺序走:
- 非生产环境重放结构变更脚本两遍,第二遍零变动。
- 凭书面执行令动手,先取备份锚。
- 按清单与台账的差集,执行待执行的结构变更脚本。
- 切换指针到新版本,做健康检查,即确认服务能启动、关键接口返回正常。
- 通过,上一版保留为回滚点;异常,指针切回上一版,只回程序,不回库。
限制与不适用
- 库里长期留着旧结构,清理要另排一步。
- 新版本写入旧版本读不懂的数据后,不能直接回代码,只能前滚。
- 没有蓝绿与金丝雀:异常靠健康检查与指针切回。
- 需要分批放量的多实例部署,不适用这套做法。
- 备份恢复指标不在这里写死,按企业要求在合同中约定。
其他做法
| 做法 | 它解决什么 | 为什么不用 |
|---|---|---|
| 回滚时连库一起回,每份结构变更脚本配一份回退脚本 | 版本与库结构始终一致 | 库里已有新数据时回库会丢数据;回退脚本每份都要写、要测,写错的代价落在最紧张的时刻 |
| 按台账尾判断执行到哪里,整批重放 | 简单 | 台账尾只记最后一个,中间缺了哪份看不出来;差集逐份核对,只做缺的 |
| 蓝绿或金丝雀,把流量分批切给新版本 | 异常只影响一部分用户 | 需要多实例与分流;SZV 的部署用目录加指针就能切换与回退,代价是没有分批放量 |
验收时可以问的问题
- 请拿一份结构变更脚本,现场看它的文件头:回滚步骤与回滚前置检查写了什么。
- 请演示一次上线中的健康检查:服务能启动、关键接口返回正常,判据各是什么。
- 新状态值已经出现之后需要回退,前滚修复由谁执行,按什么约定。
- 备份锚对应的恢复点与恢复时间,在合同里怎样约定。