数据迁移的三种场景
换数据库、换机房、升级大版本、拆分大表,这些动作都要把数据从一个库搬到另一个库。数据迁移按停机时间分为三类:可以停机的离线迁移、必须无感的在线迁移、以及边迁移边验证的滚动迁移。选哪种取决于业务容忍度,交易系统通常不能长时间停机,就只能做在线迁移。
- 全量迁移把存量数据整体搬过去。
- 增量同步用 binlog 追平迁移期间的新数据。
- 一致性校验对比新旧库保证没丢没错。
- 回滚出问题能退回去。
迁移方案设计:停机与在线
离线迁移最简单:停写、导出、导入、切流量,缺点是业务要停。在线迁移的思路是:先全量迁移存量,再用增量同步追平迁移期间的新写入,追平后短暂停写完成切换。方案设计阶段要明确迁移范围、数据量、停机预算、校验方式与回滚条件,这些写进方案文档比直接动手重要。
迁移步骤(在线):
1. 全量导出存量数据
2. 目标库导入并建索引
3. 开启增量同步追平新数据
4. 一致性校验
5. 停写切换流量
6. 观察并择机回滚
迁移窗口尽量选业务低峰,切换时预留回滚能力,宁可切慢一点也不要一锤子买卖。
全量迁移:导出与导入
全量迁移的工具各数据库都有:MySQL 用 mysqldump,PostgreSQL 用 pg_dump。导出时注意一致性快照:加事务一致性选项,保证导出的是同一时间点的数据,避免导出过程中数据还在变。导入前先在目标库建好表结构与索引,导入后再补索引往往比先建索引快。
mysqldump --single-transaction --source-data=2 \
mydb > dump.sql
mysql target < dump.sql
数据量大时用流式导出导入,避免一次性读进内存;表结构改动要提前评估,导入脚本要可重复执行,幂等防重。
增量同步:binlog 与 Canal
全量迁移后,迁移期间新产生的数据要靠增量同步追平。MySQL 的 binlog 记录了所有写操作,订阅 binlog 重放到目标库就能保持两边一致。Canal 是常用的 binlog 订阅工具,伪装成从库读取 binlog,把变更解析成结构化事件。
# Canal 配置示意
canal.instance.master.address = old-db:3306
canal.instance.dbUsername = canal
canal.instance.filter.regex = mydb\..*
增量同步要注意主键与唯一键冲突,两边库结构不同时要写映射转换;同步程序要带位点记录,重启后能从上次位置继续,不丢不重。
双写与切换
在线迁移的切换阶段,可以先把业务改成双写:新数据同时写旧库与新库,让两边都收到最新写入,再逐渐把读流量切到新库。双写会放大写入压力,还要处理两边写失败的一致性问题,所以双写通常只作为短期的过渡手段。
- 影子验证新库先不接业务,只验证写入。
- 灰度读部分读流量切到新库。
- 全量切换确认稳定后全部切过去。
切换本质是改配置与发布,要支持一键回切;流量切换后密切观察错误率、延迟与数据一致性指标。
一致性校验
迁移完成后必须校验新旧库数据一致。逐行对比在海量数据下不现实,常规做法是分片抽样加校验和:按主键范围切片,对每片数据算校验和,两库对比;不一致的片再逐行定位差异。校验可以在迁移中多次执行,最终以切换前最后一次为准。
-- 分片抽样校验示意
SELECT COUNT(*), SUM(CRC32(CONCAT(id, value)))
FROM mydb.table WHERE id BETWEEN ? AND ?;
校验工具要可重复运行,发现差异先定位是增量同步延迟还是数据真不一致;真不一致要先暂停切换,修完再校验。
回滚与演练
迁移要留后路:切换前记录旧库连接方式与配置,新库出问题能把流量切回旧库,增量同步方向反过来把新库的写入同步回旧库。回滚不是口头承诺,要提前演练一遍,把回滚步骤写成文档并跑通。
回滚检查单:
1. 旧库服务与连接是否可用
2. 反向同步链路是否就绪
3. 应用配置能否一键切回
4. 新库产生的数据是否同步回旧库
演练还能发现文档里没写到的坑,例如旧库磁盘空间、权限、连接数。没有演练过的回滚方案等于没有回滚方案。
落地清单
- 先定迁移范围、停机预算与回滚条件再动手。
- 全量导出用一致性快照,导入幂等可重跑。
- 增量同步带位点,重启不丢不重。
- 切换用影子验证、灰度读、全量切换三步走。
- 一致性校验分片算校验和,差异先定位再修。
- 回滚方案必须提前演练跑通。