数据库在线迁移这事儿,搁五年前还是件让人头皮发麻的大工程,动不动就要申请停机窗口,半夜两三点爬起来操作,业务方陪着熬,DBA顶着黑眼圈,一个不小心就是数据不一致,回滚脚本跑得比迁移脚本还勤。但现在不一样了,业务二十四小时在线成了常态,谁还敢说“周六凌晨切一下”这种话?在线迁移,零中断,平滑切换,已经从“锦上添花”变成了“必修课”。我今天不跟你聊那些高高在上的架构理论,就讲讲实战里那些坑和绕坑的法子。

先说说为什么非要在线迁。我见过太多团队,数据量就几百个G,觉得停机俩小时无所谓,结果真到迁移那天,业务方临时说“有个大促活动要上线”,或者领导突然说“今晚有个重要报表要跑”,整个计划全乱套。更现实的是,现在很多系统是微服务架构,一个核心库挂了,下游十几个服务全跟着抖,你以为只是数据库的事,其实是整个生态的事。所以在线迁移不是炫技,是被业务倒逼出来的刚需——你不想办法让切换像换灯泡一样无感,就得承受业务中断带来的连锁反应。
在线迁移的底层逻辑其实不复杂,就三步:全量拷贝、增量同步、切换流量。但每一步都有魔鬼细节。全量拷贝,听着简单,用mysqldump或者pg_dump导一下就行?真那么干,大表锁表能把线上查询堵死。实战里得用工具,比如MySQL的XtraBackup,物理备份不锁表,或者用云厂商的DTS服务,它内部做了流式读取和并发写入,能把全量阶段对源库的影响压到最低。我见过一个团队,用逻辑导出导4TB的库,跑了十个小时,期间源库CPU飙到80%,业务延迟从20ms涨到800ms,用户投诉电话被打爆。后来换了物理备份加并行恢复,四个小时搞定,源库负载只涨了5%。工具选对,事半功倍。
全量追平之后,真正的硬仗在增量同步。这里有个常见误区:以为开了binlog或者WAL日志归档就算完事。但增量同步有个致命问题叫“延迟积压”。你全量拷贝花了两小时,这两小时的增量日志可能已经堆成山,同步进程追半天追不上,业务一写多,延迟就越来越大。我见过最夸张的一次,某个支付系统做迁移,增量延迟峰值到了四十分钟,下游对账系统直接报警,数据对不上。怎么解?一是要控制全量阶段的时间,尽量缩短源库到目标库的“空窗期”;二是要实时监控同步延迟,一旦超过阈值,立刻暂停业务写入或临时切读流量,别硬扛。有些工具支持并行回放,把单线程的SQL应用改成多线程,能快好几倍,但得注意事务顺序,别为了速度把一致性搞坏了。
切换流量那一步,才是真正考验功力的地方。很多人以为改个连接串就算切换,错了。你得考虑缓存、连接池、读写分离这些周边设施。比如你的应用里用了MyBatis或者Hibernate,连接池里可能还留着旧库的长连接,直接改DNS或者配置中心,连接池不一定会立刻重建,旧连接还在往老库写数据。我见过一个案例,切换完成后两小时,发现还有一批老连接在写旧库,造成数据分裂,只能手工对账补数据,折腾了一整夜。所以切换前,一定要把连接池的“空闲连接回收时间”调短,或者干脆在切换时重启应用实例,强制断开所有旧连接。还有读写分离的场景,主从切换的顺序、延迟感知的阈值,都得提前演练。
再补一个很多人忽略的细节:数据一致性校验。在线迁移最怕的就是“以为同步了,其实漏了”。光靠工具自带的校验不够,得自己写脚本做双跑比对。我习惯的做法是,在切换前,把源库和目标库的关键表做行数对比,再抽样做字段级对比,用checksum或者哈希比对。别想着全量逐行比对,数据量大了不现实,抽样加统计是性价比最高的方案。更稳妥的做法是,在切换后的“观察期”里,同时往源库和目标库写入测试数据,跑一遍核心业务链路,确认两边结果一致再正式废弃旧库。这个观察期,我一般建议至少跑一个完整的业务高峰周期,比如一天。
还有个实战心得,就是一定要有“回滚预案”,而且要真的演练过,不是写在文档里装样子。很多团队做了在线迁移,觉得切过去就算成功,结果发现新库性能有问题、某个存储过程不兼容、或者某个SQL在新版本上走错索引,导致慢查询激增。这时候如果没准备回滚方案,就只能硬着头皮调优,业务方在旁边骂街。我的做法是,在切换前,把旧库保持只读状态保留至少一周,同时准备好一套回滚脚本,能在五分钟内把流量切回去。别心疼那点存储成本,比起出事故后的补救成本,这点钱不算什么。
再聊聊那些“看似聪明但实际坑自己”的操作。有人为了追求“零延迟”,把同步改成同步双写,应用同时写两个库,以为这样切换最平滑。但双写带来的问题更多:分布式事务怎么保证?两个库都挂了怎么办?写冲突怎么处理?我见过一个团队这么干,因为一个字段的默认值在两边库不一样,导致数据不一致,排查了两天。在线迁移的正道是“异步同步+最终一致”,别去碰同步双写,那是给自己挖坑。还有人喜欢在迁移过程中顺手升级数据库版本,比如从MySQL 5.7迁到8.0,这等于把“迁移”和“升级”两个风险叠加在一起,出了事儿你连是迁移的锅还是升级的锅都分不清。要升级,等迁移稳定运行一个月再说。
说说团队协作和运维习惯。在线迁移不是DBA一个人的事,需要开发、运维、测试一起参与。我建议迁移前至少做三次全流程演练,第一次只跑全量+增量,验证数据同步;第二次加上切换动作,验证应用连接和业务链路;第三次做故障注入,比如模拟目标库宕机,看回滚是否顺畅。演练的时候,每一步都要记录耗时和异常,形成一份“迁移操作手册”,正式执行时照着走,别临场发挥。另外,监控指标要提前配好,源库和目标库的CPU、内存、磁盘IO、主从延迟、同步延迟,全部上大屏,任何一项异常都能第一时间发现。别等到业务方反馈“页面打开慢了”才去查,那时候已经晚了。
数据库在线迁移做到零中断,说到底不是靠某个神兵利器,而是靠对细节的死磕和反复演练。全量不锁表、增量追得上、切换无感知、回滚有底气,这四句话听起来简单,每一条背后都是实打实的经验和教训。业务零中断的平滑切换,不是赌运气,是把所有可能出问题的环节都提前堵死,然后从容地按下那个切换按钮。真做到这一步,你就会发现,数据库迁移这事儿,也不过就是日常工作里的一次常规操作而已。


