Yihui’s Blog

灰度发布如何保证新旧版本数据一致?数据库结构变更怎么办?

日期:2026-07-12
标签:#面试 #八股 #后端 #灰度发布 #数据库 #Schema演进

一句话答案

使用 Expand-Migrate-Contract:先扩展向后兼容 Schema,再发布兼容新旧结构的代码,分批回填和校验,全部切换后才收缩旧字段;灰度期间避免双版本写出互不理解的数据。

面试口语版

数据库变更必须和代码分阶段发布。第一步 Expand:新增可空字段/新表,不删除、不改旧字段语义;第二步发布兼容版,读取优先新字段但可回退旧字段,写入可在同一事务双写或写旧字段后由 CDC 同步。第三步分批回填历史数据并做新旧值对账。第四步灰度新业务逻辑,确认旧版本仍能读取新数据。全部实例升级后停止旧写并观察,最后 Contract 删除旧字段和兼容代码。若新旧数据模型完全不兼容,使用版本化表、适配层或独立存储,不能强行同时写一个不兼容 Schema。

演进流程

flowchart LR
  A[Expand兼容Schema] --> B[发布双读双写兼容代码]
  B --> C[分批回填与对账]
  C --> D[灰度新逻辑]
  D --> E[全量切换]
  E --> F[Contract清理旧结构]

关键细节

  • 先 Schema 后代码还是先代码取决于变更,但任一步都必须兼容当前线上版本。
  • 双写有失败和乱序风险,同库尽量同事务,跨库用 Outbox/CDC 和版本。
  • 回滚不仅是流量回滚,新版已写数据也要旧版可理解。
  • 回填限速并记录 checkpoint,监控锁、复制延迟和业务差异。

面试官追问

  1. 双写不一致怎么办?
  2. 新版本写入了旧版本不认识的枚举值怎么办?
  3. 什么时候可以删除旧字段?

面试官追问参考答案

1. 双写不一致怎么办?

同库字段尽量在一个事务中更新;跨系统明确单一事实源,通过 Outbox/CDC 同步,事件携带版本防旧值覆盖。持续对账新旧字段,差异自动修复,切换前要求误差收敛到可接受范围。

2. 新版本写入了旧版本不认识的枚举值怎么办?

灰度前旧版本必须升级为“可容忍未知值”的兼容版,例如映射为 UNKNOWN 而非崩溃;或新值仅对新版本隔离数据启用。不能在旧代码仍在线时直接写破坏性语义。

3. 什么时候可以删除旧字段?

确认所有生产、回滚版本、离线任务和外部消费者都不再读取/写入,回填和对账完成,并经过至少一个稳定观察窗口后再删除。删除仍走在线 DDL、备份和回滚计划。

学习清单

  • 掌握 Expand-Migrate-Contract。
  • 能处理双写、回填、回滚和枚举兼容。
Maintained by · YihuiEdit on GitHub

Keep reading

View all posts