前两天和一个做技术的老朋友吃饭,他吐了一肚子苦水:公司要做数据库迁移,数据量倒是不大,但偏偏是那种每天都会产生几百万条新记录的“增量型”业务。他试了好几种方案,要么迁移过程中业务中断,要么数据对不上,搞得他三天两头加班到凌晨。我听完笑了,这不就是数据库增量迁移这个“老问题”的典型症状吗?很多团队一上来就想着全量复制,以为把数据一股脑倒过去就完事了,结果增量数据这块,就像狗皮膏药一样,贴上去撕不掉。

其实增量迁移的核心难点,说白了就是三个字:一致性。想象一下,你在 A 库这边做迁移操作,B 库那边业务还在源源不断地写入新数据。你这边刚把一批记录搬过去,那边又冒出来几十条。就像一边往桶里倒水,一边水龙头还在开,桶里的水永远没法“静止”。很多初级方案比如直接靠时间戳或自增 ID 来筛选增量数据,听着简单,但现实里要么业务系统的时间戳不准,要么 ID 序列因为回滚或分布式环境变得乱七八糟,对账对得让人崩溃。
我见过最离谱的案例,是某电商平台做迁移时直接用了“双写”策略——业务代码同时往新旧两个库写数据。理论上没问题,但实际跑起来,因为网络延迟和数据库锁机制,经常出现旧库写成功、新库写失败的情况,两个库的数据永远差那么一截。那哥们后来花了整整两周时间手动对账,整个人都快神经质了。所以,增量迁移的成败,往往不在技术方案本身,而在于你有没有把“一致性”这根弦绷紧。
那有没有经过验证的好路子?我聊过的几个大厂 DBA,普遍认可的方案是“日志解析+回放”。具体来说,就是利用数据库自带的 binlog 或 redo log,捕捉所有增量变更,然后把这些变更按事务顺序在新库上重新执行一遍。这个思路的好处是,它不依赖业务系统的时间戳,也不依赖业务代码的配合,纯粹从数据库底层抓取数据,准确率极高。像 MySQL 的 Canal、Oracle 的 GoldenGate,都是基于这个原理。
但这个方案也有坑。最典型的是日志解析的延迟问题。如果业务量特别大,比如每秒几千笔交易,日志解析组件可能跟不上写入速度,导致增量数据堆积。我有个做金融系统的朋友,他们用 Canal 做增量迁移,结果在一次业务峰值时日志积压了十几分钟,新库那边数据落后了一大截,差点引发线上事故。他们的教训是:解析组件的消费能力必须提前压测,而且要有降级预案,比如临时切回全量同步,或者用消息队列做缓冲。
另一个容易被忽略的环节,是增量迁移过程中的数据校验。很多人觉得日志解析既然是从底层来的,就一定没问题。但现实是,网络丢包、磁盘坏道、甚至解析组件自身的 bug,都可能导致数据丢失或写错。我认识的一个数据工程师,他们在迁移一个千万级用户表时,遇到了 binlog 解析漏掉某条更新的情况,结果旧库的用户信息更新了,新库却没变。后来不得不做全量对账才发现问题。所以,不管方案多高级,校验这一步千万不能省。最好在迁移过程中不停抽样比对,甚至做全量哈希校验。
说到校验,就不得不提增量迁移的“断点续传”能力。迁移过程动辄几个小时甚至几天,中间随时可能因为网络抖动、系统重启而中断。如果每次中断都要从头开始,谁也受不了。我见过一种比较聪明的做法,是在迁移工具里记录一个“checkpoint”,比如日志的偏移量或事务的序号。一旦中断重启,工具自动从上次断掉的地方继续拉取增量数据。这个机制看似简单,但实现时需要小心,因为有些日志是顺序的,偏移量记错了就会乱套。
另外,生产环境做增量迁移,还得面对“脏数据”问题。很多旧系统的数据质量本身就不佳,字段类型不合规、编码错误、甚至空值很多。在增量迁移过程中,这些脏数据会原封不动地同步到新库。想想看,旧库还能勉强支撑业务,新库一上线就被脏数据搞崩。聪明的团队会在迁移前先做一轮数据清洗,或者在迁移工具里加上过滤规则,比如遇到某个字段为空时自动填充默认值或直接跳过。
我想聊聊增量迁移的“灰度”思路。很多人做迁移,喜欢搞“一刀切”,旧库停服,新库上线。但这种方式风险太大,一旦新库有问题,业务直接瘫痪。更稳妥的做法是让新库和旧库并行运行一段时间,比如一周或一个月,期间只把部分读流量切到新库,写流量继续走旧库。等增量数据完全对齐并验证没有差异后,再逐步切写流量。这种“灰度切换”虽然慢,但安全可靠,我见过不少大厂都是这么干的。说到底,数据库增量迁移不是炫技,而是工程实践,慢一点、稳一点,比什么都强。下次再遇到这个问题时,想想是追求快,还是追求稳。


