迁移策略与模式:全量迁移、增量迁移、双写迁移
数据迁移不是简单的「把A搬去B」。选错模式,后面全得重来。我记得刚带团队那会儿,有人拍脑袋选了全量,结果30TB的数据跑了三天三夜,业务方天天催,最后回滚比迁移还痛苦。
你想想看,迁移模式直接决定你的停机窗口、数据一致性和回滚复杂度。我个人习惯把这个章节放在最前面讲——先把策略定了,后面的SDK适配才有方向。
全量迁移——最直接,也最暴力
全量迁移就是把源头数据一股脑全倒过去。听起来简单,实操里到处都是坑。
什么时候用?数据量小(百GB以内),业务允许长时间停机。比如内部系统升级、老系统下线。
全量迁移的核心流程
- 导出全量数据(mysqldump / pg_dump / 快照)
- 传输至目标环境
- 目标库导入
- 校验行数和关键字段
- 切换流量
优点很明显:逻辑简单,回滚也简单——保留源库备份就行。但缺点同样致命:停机时间等于数据搬完的时间。我在项目中遇到过一家金融公司,50GB数据用带宽跑了一个半小时,业务中断直接导致KPI崩盘。
我曾经踩过的坑:全量迁移时忘了关外键检查,导入到一半报错,数据没完全落地,源库又没做一致性快照,最后只能重新导出。从那以后我定了个规矩——全量迁移前必须打快照,并且开一个事务级别的导出。
增量迁移——细水长流,但别松了那根弦
增量迁移只搬变化的数据。说白了,就是先做一次全量基线,然后持续同步增量。我偏爱这个模式,因为它可以做到近乎零停机。
增量数据怎么抓?三种主流玩法:
- 时间戳/版本号:最常用,比如 updated_at 字段。注意时区和精度问题。
- CDC日志(Change Data Capture):解析 binlog、redo log。准实时,但不支持所有数据库。
- 触发器:建个变更表记录增删改。简单但影响源库性能,我一般不推荐。
我的经验:用时间戳做增量时,一定要处理“时间回拨”和“精度丢失”。有一次业务端双写时改了系统时间,导致一批数据没被扫到,丢单了。后来我统一用协调时钟 + 微秒级时间戳才搞定。
增量迁移最难的地方在于一致性校验。源和目标一直在变,你怎么证明两边数据最终一致?我个人习惯在增量同步结束后,做一轮全量比对,如果差异超过阈值就重跑。
双写迁移——最稳妥,也最复杂
双写迁移不是「先写A再写B」,而是同时写入旧系统和新系统。你想想看,用户写一条数据,两个地方都落盘。等校验通过后,再切到只写新系统。
我为什么偏爱双写?因为它能提供最强的回滚能力——切过去发现不对,把流量切回旧系统就行,数据不会丢。但代价也最高。
双写迁移的标准步骤
- 部署SDK代理层,拦截写入请求,同时转发给旧库和新库
- 后台异步比对两边写入结果
- 比对一致率超过99.99%后,持续观察一段时间
- 切换读流量到新系统
- 等待确认正常后,关闭旧库写入
我曾经翻车的一个案例:双写SDK里的重试机制没控制好,新库写入失败后一直重试,导致旧库正常但新库堆积了大量重复数据。回滚时发现新库数据「多」了,比对数小时才排查出来。从此我规定:双写阶段新库写入失败只记录日志,不重试,由事后补偿任务处理。
三种模式对比
| 维度 | 全量迁移 | 增量迁移 | 双写迁移 |
|---|---|---|---|
| 停机时间 | 长(等于迁移耗时) | 短(仅切换窗口) | 几乎为零 |
| 数据一致性 | 高(单点快照) | 中等(需校验) | 高(实时比对) |
| 回滚难度 | 低(保留源库) | 中(需恢复增量) | 低(切回旧库) |
| 实现复杂度 | 低 | 中 | 高 |
| 适用场景 | 小数据、允许停机 | 大数据、可接受少量不一致 | 核心交易、零容忍停机 |
我个人的选择建议:如果让我选,小数据(< 100GB)且能接受停机,用全量,简单暴力;大数据(TB级)且能容忍短暂不一致,用增量;核心支付转账业务,别犹豫,直接上双写,虽然开发量翻倍,但能睡个安稳觉。
三种模式没有的优劣。我见过有人把全量+增量组合成「基線+实时同步」,也见过双写融合了回滚SDK。关键还是那句话——选模式之前,先想好怎么回滚。下一节我们会深入研究每种模式对应的SDK接口设计,但先把策略理清,后面的代码才不会走偏。
嗯,说到代码,其实全量迁移的Python脚本也就几十行,但增量迁移的binlog解析库选型能扯半天。这部分内容我们放到SDK适配的章节详细展开。