这事儿得从上周说起。朋友老张半夜给我打电话,声音慌得不行:“完了完了,服务器硬盘报警,MySQL 数据得赶紧挪,不然明天业务就瘫了。”我一边安抚他,一边在心里盘算——Linux 下 MySQL 数据库迁移,这事儿说大不大,说小不小,但真要是没提前规划好,踩坑踩得你怀疑人生。老张就是典型的“平时不烧香,临时抱佛脚”,数据库跑了好几年,迁移方案从未演练过,连备份文件放哪儿都得在服务器上现场找。

我让他先别慌,第一步不是动手,而是把环境摸清楚。你得知道源数据库的版本、字符集、存储引擎、数据量大小,还有业务对停机时间的容忍度。老张查了一圈,MySQL 5.7,InnoDB 为主,数据量大概 80 GB,业务允许凌晨两点到四点停机两小时。我听完松了口气,这个量级不算恐怖,但两小时窗口还是有点紧。最关键的是,他要从腾讯云搬到阿里云,跨云迁移,网络带宽只有 100 M,80 GB 的数据裸传至少得一个半小时,再加上校验、切换、回滚方案,两小时真得掐着秒表算。
迁移方案我给他定了三步走:先用 mysqldump 全量导出,再用 scp 传到新服务器,用 source 导入。听着简单,但细节全是坑。比如 mysqldump 的参数,很多人习惯用默认,结果导出时带上了一堆无关数据,或者没加 导致锁表。我让老张必须加 ,确保 InnoDB 一致性读取,不锁表,同时把存储过程、触发器、事件都带走。他导出完一看,SQL 文件 12 GB,压缩后 3.8 GB,传了半小时。
传完文件,第二关是导入。老张傻乎乎地直接 ,结果跑了十分钟没动静。我问他新服务器的参数调了没有?他愣住。MySQL 导入大文件,默认的 只有 4 M,12 GB 的 SQL 文件里随便一条插入语句就会撑爆。我让他改成 256 M,同时把 调到服务器内存的 70%, 调大到 512 M, 关掉,导入完再开。他改完参数重启 MySQL,再跑 source,四十分钟搞定。你瞧,很多所谓“迁移失败”,根本不是数据有问题,而是参数没调对。
导入完成后,老张急着切业务,我按住他:先做数据校验。最简单的办法是比对源库和目标库的表记录数。我写了个脚本,遍历所有非系统库的表,,然后 diff 一下。结果发现有三张表记录数不一致,差了十几条。老张脸都白了,以为是数据丢失。我查了一下,原来是导出过程中有少量写入,虽然 mysqldump 加了 ,但 DDL 操作不受事务隔离。解决办法是导完后锁表再导一次增量,或者直接用 binlog 回放。老张最终选择锁表 5 分钟,重新导出那三张表,这次对了。
数据一致后,还得做业务验证。我让老张在新服务器上搭一个临时业务环境,跑几个核心接口,抽查几条关键数据。比如用户表、订单表,随机抽几条,对比源库的值。这一步很多人嫌麻烦跳过,结果上线后才发现某个字段类型变了,或者字符集乱码。老张运气好,没踩这个坑,但他发现新服务器的时区设置和源库不一样,导致时间字段整体偏移了 8 小时。我让他修改 和 MySQL 的 参数,重启后正常。
切换那天凌晨,老张按计划停掉源库的写入,跑完一次增量备份,然后修改 DNS 解析,把业务流量指向新服务器。整个过程花了 1 小时 50 分钟,离两小时窗口还有 10 分钟。他长舒一口气,发了个朋友圈:“数据库迁移,一次过。”我没忍心告诉他,真正的考验是监控。迁移完的 48 小时是观察期,要盯着慢查询日志、连接数、磁盘 I/O,看看有没有隐藏问题。果然,第二天下午他发现有个报表查询在新库上跑得特别慢,原来新服务器的磁盘是 HDD 而不是 SSD,索引优化没跟上。
这次迁移让我想起一个道理:数据库迁移不是技术活,而是管理活。技术方案网上到处都有,但真正决定成败的,是对细节的敬畏。比如网络带宽够不够,参数调没调,校验做没做,回滚方案有没有。老张后来请我吃饭,说下次一定提前演练。我说不用等下次,你现在把这次迁移过程写成文档,把踩过的坑、改过的参数、跑过的命令都记下来,下次照着做就行。他点头,又补了一句:“还得加个前提——别等到硬盘报警才想起来迁移。”
其实很多 DBA 都犯过老张的错,觉得数据库跑得好好的,迁移是“万一”的事。但互联网行业没有“万一”,只有“一万”。你永远不知道硬盘什么时候坏,云厂商什么时候断网,业务量什么时候暴涨。与其等到火烧眉毛再搬家,不如平时就把迁移方案当成常规演练。哪怕只是从一台物理机迁移到另一台,也能帮你熟悉流程、发现问题。毕竟,数据库迁移这事儿,看起来是数据在搬家,实际上是人心的定力在考试。


