说实话,看到“无缝迁移”这四个字,我第一反应是:这世界上真有“无缝”这回事吗?干了十几年数据库,我太清楚了,所谓的无缝,不过是把该踩的坑提前踩了,该流的汗提前流了。但既然大家想要一个指南,那我就把那些血泪教训揉碎了,摊开了,讲给你们听。

先说说迁移这事儿到底是啥意思。很多人以为就是把数据从A库搬到B库,跟搬家似的,东西搬过去就行。错了。MySQL迁移最要命的是业务不能停,用户不能感知。你想想,电商大促期间做迁移,要是让用户下单失败,那损失可不是几个工程师的加班费能兜住的。所以,真正的迁移,是数据完整、性能不降、业务不中断的三重考验。我见过太多人,准备工作做三天,迁移执行两小时,结果回滚花了一周。
准备工作这块,很多人上来就开干,结果发现源库和目标库的字符集对不上,或者存储引擎不一样,甚至表结构设计都天差地别。我建议你先做个“体检”:看版本差异,看字符集,看存储引擎,看分区表,看触发器、存储过程、函数这些容易忽略的“定时炸弹”。比如,从MySQL5.7迁到8.0,有些语法已经废弃了,直接迁移会报错。还有,如果源库用了MyISAM引擎,目标库换成InnoDB,那索引策略、事务处理逻辑都得重新评估。
数据导出这块,我见过最蠢的做法是直接用mysqldump一把梭,几TB的数据导出来,文件大到磁盘都装不下。更离谱的是,有人用默认参数导出,结果字符集乱码,导入的时候哭都来不及。正确的做法是:如果数据量小(比如几十GB以内),mysqldump加–single-transaction参数保证一致性,再用–quick参数避免内存撑爆。如果数据量大,那就得用mydumper或者Percona工具做并行导出,或者直接走数据文件拷贝。但文件拷贝有个坑:必须保证源库和目标库的版本、配置、数据目录结构完全一致,否则导入直接报错。
数据导入更考验耐心。很多人以为导出一小时,导入也一小时,结果发现目标库的磁盘IO直接被打满,业务响应延迟飙升。我这边的经验是:先关闭binlog,关闭外键检查,调整innodbflushlogattrx_commit参数到0(当然,得接受数据丢失的风险),然后分批提交。如果是用mysqldump导入,加–disable-keys参数可以省去重建索引的时间。还有个骚操作:先把数据导入到一个空表的临时库,再rename表名切换,这样对业务影响最小。
数据一致性校验,这才是真正的照妖镜。很多人把数据搬过去,跑个简单的count()就以为完事了。我告诉你,count()能对上不代表数据一致。得做行级比对,尤其是大字段、时间戳这种容易出问题的类型。我推荐用pt-table-checksum,它能逐行计算checksum,然后对比源库和目标库的差异。但要注意,这个工具在源库负载高的时候会拖慢性能,最好在业务低峰期跑。如果发现不一致,别慌,用pt-table-sync能自动修复,但修复前一定要确认好规则,别把对的改错了。
业务切换这一步,最考验胆量和经验。很多人喜欢搞“先切DNS,再切数据库”这种顺序,结果DNS缓存导致一部分用户连到新库,一部分还在老库,数据直接分裂。正确的做法是:先把应用层配置改成新库地址,灰度发布一小部分流量,观察半小时以上,确认没问题了再全量切换。但注意,切换前一定要确认老库还在,而且有备份。万一新库挂了,你还能秒回老库。还有个细节:切换后要持续监控慢查询、连接数、磁盘IO,至少观察24小时,因为有些问题要等业务高峰期才会暴露。
说个大家容易忽略的点:迁移后的清理和优化。很多人数据迁完,业务跑起来了,就以为大功告成。结果新库跑了一周,磁盘空间报警,一查才发现是binlog没及时清理,或者慢查询日志开得太大。还有,新库的缓冲区、连接数这些参数往往需要重新调优,因为数据量、访问模式可能跟老库不一样。我建议迁移完成后的一个月内,每周做一次性能评估,该加索引的加索引,该调参数的调参数。千万别觉得“搬完就完事了”,数据库运维是个持续活。
写到这里,你可能会觉得,这哪里是无缝,分明是步步惊心。但这就是现实。所谓无缝迁移,不过是把风险提前识别、提前化解,让用户感觉不到变化而已。如果你真要动手做一次迁移,记住三件事:第一,永远留好回滚方案;第二,永远在测试环境先跑三遍;第三,永远别。数据库打交道这么多年,我最大的心得就是:敬畏数据,敬畏业务,敬畏每一行SQL。


