← [ BACK_TO_NOTES ]

数据库 Schema Migration 与发布兼容性

解释数据库 schema 变更为何不能等同于应用二进制回滚,并用 expand-and-contract、回填、双写和兼容窗口组织安全发布。

#synthesis #evergreen #backend #architecture

[!info] related notes

数据库 Schema Migration 与发布兼容性

核心结论

应用镜像通常可以切回旧版本,但数据库 migration 可能已经:

  • 删除或重命名列;
  • 改变类型;
  • 重写或合并数据;
  • 建立旧代码不理解的新约束;
  • 在大表上持有长锁。

因此“应用回滚”不等于“数据库 down migration”。安全发布更依赖新旧应用与新旧 schema 的兼容窗口。

Expand-and-Contract

Expand

先做向后兼容扩展:

  • 新增 nullable / 有默认策略的字段;
  • 新建表或索引;
  • 保留旧字段;
  • 新代码同时理解旧数据和新数据。

Migrate

  • 后台回填历史数据;
  • 双写或由事件/CDC 同步,并定义部分成功、重试、顺序和一致性校验;
  • 观察差异、失败和回填进度;
  • 把读流量逐步切到新字段。

Contract

确认所有旧版本退出、回填完成、读写已切换后:

  • 停止旧字段写入;
  • 删除兼容代码;
  • 最后删除旧列、表或索引。
Expand schema
→ Deploy compatible code
→ Backfill / dual-write
→ Switch reads
→ Verify
→ Remove old path
→ Contract schema

为什么 Down Migration 不一定安全

DROP COLUMN 的反向 SQL 可以重新建列,却不能恢复原数据;类型压缩、聚合和数据修正也可能不可逆。生产事故时通常优先:

  1. 停止扩量;
  2. 切回仍兼容新 schema 的应用版本;
  3. 禁用新功能或写路径;
  4. forward-fix;
  5. 只有确认无数据损失时才执行 down。

常见变更

新增 NOT NULL 字段

安全路径通常不是直接给大表加无默认值 NOT NULL:

  1. 新增 nullable 字段;
  2. 新代码开始写;
  3. 分批回填;
  4. 校验无 null;
  5. 再加约束。

具体数据库版本可能支持更高效的 metadata-only 操作,仍应按真实版本和表规模验证。

重命名字段

跨版本发布中可先新增新字段,双写或兼容读取,完成迁移后再删除旧字段。一次 RENAME 可能让旧应用立即失败。

新 enum 值

旧客户端或旧服务可能无法 parse 新值。先让消费者具备所需处理能力,再由生产者发出新值;只有语义允许时才能安全降级。权限、支付和终态等关键 enum 的未知值应明确拒绝或进入待处理状态,不能随意映射为默认成功。

建索引

大表建索引可能影响写入或持锁;使用数据库支持的 online/concurrent 方式时,也要观察资源、失败和 invalid index 状态。

多副本与 Migration Job

不要让每个应用副本在启动时无协调地执行 migration。更可控的是:

CI 验证空库与升级路径
→ 单独 Migration Job
→ 兼容性检查
→ 应用 rollout
→ post-deploy verification

迁移账号和运行时账号应分离权限。

回填任务

回填本身是生产数据任务,需要:

  • batch / cursor;
  • checkpoint;
  • idempotency;
  • rate limit;
  • retry / dead-letter;
  • 进度和差异指标;
  • 暂停 / 恢复;
  • 数据校验。

不要把几千万行更新塞进一个不可观测事务。

发布门禁

  • 在空库跑完整 migration;
  • 从最近生产 schema snapshot 跑升级;
  • 验证旧应用 + 新 schema;
  • 验证新应用 + 旧/过渡 schema(按策略);
  • 测量大表 DDL / backfill 时间和锁;
  • 准备 feature flag、停止扩量和 restore 方案;
  • 记录 schema version 与部署 revision。

面试回答

应用二进制可以回滚,但数据库变更可能已经丢数据或改变约束,所以不能把 down migration 当普通回滚。更稳的是 expand-and-contract:先做向后兼容扩展,部署同时兼容新旧 schema 的代码,回填或双写并切换读路径,确认旧版本退出后才删除旧字段。事故时优先切回兼容应用、关闭新写路径或 forward-fix,而不是无脑逆向 DDL。

创建于 2026/9/2 更新于 2026/10/6
Digital Biome
Access

键盘导航

j / k / ↑ / ↓
选择对象
Enter / o
打开选择
/ 或 Ctrl+K
全站搜索
i / f / 1–4
筛选当前列表
g → h / l / p / t / a
首页 / 笔记 / 项目 / 工具 / About
r → 1–9
打开所选对象的关联
u
返回上一页
Esc
关闭浮层 / 取消命令;输入框内清空文本