导语:迁移是数据库工程的最高危操作
数据库迁移(升级版本、换云、拆分、改表结构)一旦在过程中丢失数据或长时间不可用,损失是灾难级的。成功的迁移靠的不是运气,而是一套可验证、可回滚、可灰度的方法论。
一句话总结: 数据库迁移的黄金法则是「全量 + 增量 + 双写 + 校验 + 灰度 + 回滚」六步闭环——每一项都是在为「不丢数据、不停服务、可快速复原」兜底。
1. 迁移场景与方案选型
1.1 常见迁移场景
| 场景 | 特点 | 典型手段 |
|---|---|---|
| 同构迁移(MySQL→MySQL) | 结构几乎不变 | mysqldump + binlog 增量 / Mydumper |
| 版本升级(5.7→8.0) | 底层变化大 | 官方升级工具 + 全量校验 |
| 异构迁移(Oracle→MySQL/PG) | 语义差异大 | 专用工具(如官方 + 手写转换) |
| 云厂商迁移 | 网络/规格差异 | DTS/迁移服务 + 增量追平 |
| 分库分表后归并 | 数据分布变化 | 双写 + 校验 + 灰度 |
1.2 迁移方案三要素
① 全量迁移:把存量数据完整搬到目标库
② 增量迁移:把存量搬完之后产生的变更持续同步
③ 校验切换:确认两边一致后,才把读/写切到目标
任何只做 ①② 不做 ③ 的迁移,都是自欺欺人的"搬迁",不是"迁移"。
一句话总结: 方案选型围绕 全量 + 增量 + 校验 三件套,具体工具取决于同构/异构与厂商绑定。
2. 全量迁移:快照一致性问题
2.1 朴素 dump 的坑
直接 mysqldump 全表导出、再导入目标库,会遇到一致性与时间差问题:
# 朴素 dump:导出期间产生新写入,两端对不上
mysqldump -u root db orders > orders.sql
# 此时 orders 里又有新数据写入 → 无法证明两端一致
2.2 一致性快照 + binlog 位点
正确姿势:先建立一致性备份,同时记录 binlog 位点(GTID),再开启增量追位。
# 1) 全量:带 --single-transaction(InnoDB MVCC 快照)导出一致快照
mysqldump --single-transaction --set-gtid-purged=OFF -u root db > snapshot.sql
# 2) 记录起始位点
SHOW MASTER STATUS;
# File: mysql-bin.000003 Position: 2345
# 3) 导入目标库
mysql -h target -u root db < snapshot.sql
# 4) 从位点 2345 起,用 CDC 工具回放增量 binlog
# (Canal / DTS 订阅 binlog,catchup 到接近实时)
全量迁移必须带一致性快照,并记录 binlog 位点作为增量起点。缺了位点,增量无从谈起。
3. 增量同步与双写
3.1 增量同步的两种路径
| 路径 | 机制 | 场景 |
|---|---|---|
| binlog/CDC 单向同步 | Canal/DTS 订阅源库 binlog 回放目标库 | 迁移期间"只读源"接受写入 |
| 应用层双写 | 业务代码同时写源库 + 目标库 | 需要业务双端一致 |
纯 binlog 单向同步的局限:目标库不可写(否则回放会冲突)。等数据追平后切换写流量即可。
3.2 双写切换(灰度阶段高可用切换)
当两种库语义差异大、无法唯 binlog 回放时,用双写过渡:
双写阶段拓扑:
应用 → 写源库 ✓ 写目标库 ✓
↓ ↓
(源可回滚) (目标验证)
校验通过 → 流量切到目标 → 观察期(如 1~4 周)
→ 全量校验仍一致 → 关闭源库写入 -> 迁移完成
双写阶段是回滚的保险:任何异常,一瞬间把读/写切回源库即可。双写要用事务/异步队列保证两边至少最终一致,并用对账作为兜底。
一句话总结: 回滚的底气来自双写——只要源库还接受请求,任何切换到目标库后的意外都能快速回退。
4. 数据校验:迁移质量的唯一证明
迁移没有"信任",只有"校验"。(核心) 校验做得多,切换才敢做得快。
4.1 全量校验(逐行对账)
-- 对两端逐行做 checksum 对比
SELECT COUNT(*) FROM orders; -- 行数一致
SELECT CRC32(GROUP_CONCAT(id)) FROM orders; -- 抽样校验
4.2 抽样 + 一致性校验
推荐校验动作:
1. 行数校验:两端 count 一致
2. 抽样字段一致性:对主键/时间/状态等关键列做 CRC 对比
3. 全量慢校验:业务低峰用 SELECT SUM/CRC 连表做全量对账
4. 校验窗口:迁移期间持续对账,确保增量也没丢
一句话总结: 校验是迁移的唯一"合格证"。不做全量 + 增量双重校验的直接切换,等于把风险裸奔上线。
5. 灰度切换与快速回滚
5.1 分层灰度
灰度路径:
① 只读副本(目标库只作为读副本,10% 读流量)
② 大流量校验通过 → 切主读
③ 业务切写(通常是双写/物理切换)
④ 参数回滚窗口:低频接口保留读源库
关键:每个阶段都有独立可逆的旋钮,
而不是一次大爆炸式切换。
5.2 回滚预案(必须提前写)
# 预写回滚脚本,切换前所有人会签字
# 内容模板:
# 1) 把写流量重新指回源库
# 2) 停止对目标库的写入
# 3) 回放 binlog 至切换点,追平目标库的滞后
# 4) 校验回滚后一致
# 回滚成功标准:源库写正常、数据与切换点对账一致、无脏数据残留
一句话总结: 切换要能步步可逆;回滚预案必须在切换前写好并评审签字,而不是切换后才临时写。
6. 迁移避坑清单
| 坑 | 后果 | 对策 |
|---|---|---|
| 全量 dump 无一致性快照 | 两端对不上、丢数据 | –single-transaction |
| 漏记录 binlog 位点 | 增量无法续接 | SHOW MASTER STATUS 记录 GTID |
| 跳过独立增量工具硬灌 | 写入冲突/失真 | 用 CDC/双写 |
| 不做校验就切写 | 数据不一致无感知 | 全量 + 抽样对账 |
| 一次性切主 | 无法回滚、爆炸半径大 | 分级灰度 |
| 迁移后不留回滚窗口 | 出问题恢复慢 | 保留 1~4 周观察期 |
| 异构类型映射错误 | 精度/字符集失真 | 类型映射表逐一核对 |
7. 总结
数据库迁移没有银弹,只有纪律。完整闭环:
| 环节 | 关键动作 |
|---|---|
| 选型 | 同构/异构定工具,围绕 全量+增量+校验 |
| 全量 | 一致性快照 + 记录 binlog 位点 |
| 增量 | binlog/CDC 同步,必要时应用双写 |
| 校验 | count/CRC/全量对账,迁移期间持续 |
| 切换 | 分级灰度,每级独立可逆旋钮 |
| 回滚 | 预案前置书写,切换后保留观察窗口 |
一句话记住:迁移不可怕,可怕是「只有搬数据、没有证明」。全量、增量、双写、校验、灰度、回滚六步——每一步都是给"数据不丢、不停服、能回退"这三个目标上锁。系数齐了,迁移就从"高风险赌博"变成"常规操作"。
延伸阅读
继续阅读
探索更多技术文章
浏览归档,发现更多关于系统设计、工具链和工程实践的内容。