# 实践中的零停机数据库迁移

用扩展再收缩的交付方式，在真实流量下安全变更 schema。

Published: 2024-06-05

## 部署会重叠

Schema 迁移很少孤立运行。新旧应用实例可能同时服务流量，worker 可能处理延迟任务，移动客户端可能数月仍活跃。安全迁移假定这种重叠，并保持每个中间状态兼容。

扩展再收缩模式把有风险的替换拆成可逆阶段。先扩展 schema 或接口，再迁移行为与数据，观察结果，之后才移除旧路径。额外步骤在关键时刻买来控制。

## 扩展而不改变含义

以现有代码可忽略的方式添加新的可空列、表、索引或端点。避免在不理解数据库行为时，用默认值或约束在锁下重写大表。在引擎支持时并发构建大索引，并监控复制滞后与锁持有时间。

部署可写入两种表示或为新创建数据填充新模型的代码。双写引入一致性风险，因此保持过渡有界，对分歧做埋点，并在两条记录共享同一数据库时优先单事务。

- 先衡量表大小与锁行为
- 让迁移命令可重启
- 在生产负载下节流回填
- 用稳定检查点记录进度

## 把回填当作一项操作

生产回填是工作负载，而非一次性脚本。处理确定性批次，持久化检查点，限制并发，并暴露进度与失败。任务应可安全停止与恢复，且不重复效应。

持续验证新表示。比较计数、校验和、不变量与抽样记录，而非等到结束。若迁移改变含义，把预期映射编码为领域所有者审阅过的可执行检查。

## 有意移动读取

一旦新写入与历史数据就绪，在功能开关或受控发布后切换读取。影子读可比较新旧结果而不改变用户响应。按路径分段错误与延迟，使推进决策基于证据。

此阶段的回滚通常意味着切回读取，而非反转 schema。破坏性回滚脚本可能让可恢复部署变得糟得多。在信心足够高之前保留扩展状态。

## 仅在证据之后收缩

停止写入旧表示，等待重叠应用版本与排队工作清空，然后移除未用代码。通过遥测确认旧字段或表不再被读取后，再在单独部署中删除它。

零停机不是没有风险。它是一种使风险可观测、限制爆炸半径，并在每个阶段保留安全决策的交付形态。
