上周三凌晨两点,我盯着屏幕上的迁移进度条,手心全是汗。旁边的运维小哥递来一杯咖啡,随口说了一句让我至今难忘的话:“数据库迁移就像给飞驰的赛车换轮胎,技术不重要,心态才重要。”这话虽粗,却有理。MySQL不停服迁移听起来像是个技术活,实际上更像系统工程。你不仅要懂数据库,还要懂业务逻辑、备份策略、监控告警,甚至要懂点心理学——怎么让业务方安心。

说实话,早期的迁移方案相当粗暴:停服、导出、导入、校验,一套流程下来,少则半小时,多则几小时。对中小公司还好,对电商、金融这类业务,半小时的停机可能就意味着几百万的损失。后来大家开始琢磨,能不能不停服就把数据搬过去?答案是可以,但代价是你必须接受一个事实:不停服迁移的复杂度,比停服迁移高出一个数量级。你需要处理增量数据的实时同步,解决主键冲突,保证数据一致性,还得做好回滚预案。
先说最常用的方案:主从复制 + 灰度切换。思路其实很简单,先在目标服务器上搭建从库,从原主库拉取 binlog,追平数据。等延迟降到零或接近零后,再通过修改 DNS 或负载均衡,把写流量切到新库。听起来顺畅,但坑藏在细节里。比如,binlog 格式必须是 ROW,不能是 STATEMENT,否则某些函数操作会导致数据不一致。再比如,切换那一刻必须确保所有长事务已经提交,否则切换后会出现数据丢失。我见过有人踩这个坑,切完后订单表少了十几条记录,只能手工补数据,场面相当狼狈。
另一个常用方案是双写迁移。业务代码同时写入新旧两个库,新库逐步接管读流量。好处是回滚方便——发现新库有问题,只需把代码切回旧库,不必动数据库本身。缺点也很明显:需要改业务代码,而且对高并发场景不友好。双写意味着每次写入都要多一次网络开销,还要处理两个库写入结果不一致的异常。我见过团队使用该方案,结果新库写入超时,业务方误判为写入失败,前端报错刷屏,最终只能回滚。因此,双写适合低并发、对一致性要求高的场景,如用户配置、权限数据等。
还有一种进阶玩法:基于消息队列的异步迁移。业务发出数据变更消息,消费者同时更新旧库和新库。理论上最优雅,解耦彻底,不停服,还能平滑切换。但实际落地时会发现,消息队列本身的不确定性会引入新问题。比如,消息重复消费怎么办?消费者挂了怎么办?新旧库数据不一致怎么检测?这些问题的处理比主从复制复杂得多。我接触过几家金融科技公司,他们用 Kafka 实现该方案,配套写了数据校验的定时任务,每小时跑一次,发现差异自动修复。但即便如此,偶尔仍会有漏网之鱼,需要人工介入。
不管选哪个方案,数据校验是绝对不能省的环节。很多人觉得迁移后数据量对得上就行,但这并不代表每条记录都正确。可以用 checksum、MD5 对比每张表的每一行数据,也可以使用第三方工具如 pt‑table‑checksum。校验完后,还要做业务层面的验证,例如随机抽取几条用户数据,检查旧库和新库返回的结果是否一致。我见过最极端的情况:某团队迁移完后,数据量和 checksum 都对上了,结果业务上线后用户登录一直报错。排查发现,旧库的某个索引字段编码是 utf8,新库是 utf8mb4,导致字符串比较出错。这种坑工具查不出来,只能靠业务逻辑覆盖。
还有一个容易被忽略的点:迁移窗口的选择。理论上不停服迁移可以随时进行,但实际操作中仍需考虑业务低峰期。比如凌晨两三点,大部分用户都在睡觉,写流量降到最低,这时切换失败的回滚成本也最低。但别忘了,低峰期往往也是 DBA 最忙的时候。我建议提前写好切换脚本,做好演练,甚至录个操作视频,避免临场手忙脚乱。另一个细节:切换那一刻要提前通知业务方,让他们停止发版、停止跑批任务。哪怕只停几分钟,也能避免很多不可控因素。
回滚预案这块,很多人觉得“既然不停服,回滚就是改个 DNS 的事”。但现实是,DNS 有缓存,TTL 再短也可能让用户请求卡在旧连接上。而且,如果使用双写方案,回滚时还得处理新旧库之间可能产生的数据差异。我见过一个案例:某团队用双写迁移,切到新库后三天发现性能不佳,决定回滚。结果回滚后,旧库里多了三天的新数据,而新库里的数据又没有全部同步回来,两边对不上,只能人工逐条核对。所以,回滚预案不能只写“切回去”三个字,需要明确回滚后以哪个库为准,差异数据怎么处理,业务方需要做哪些配合。
说个观点:不停服迁移技术方案只占 30%,剩下的 70% 是流程管理和风险控制。你必须有详细的迁移计划、明确的验收标准、回滚触发条件,还要有值班表、沟通群,甚至心理准备。我见过太多团队,技术方案写得完美,却因为没人通知业务方、没人监控切换后的慢查询、没人关注磁盘空间而翻车。数据库迁移本质上是业务连续性的缩影,处理得好,大家觉得理所当然;处理不好,所有人都会记住你。所以,别迷信某个工具或方案,多想想“万一失败了怎么办”。这种思路放在任何技术决策上都适用。


