上周帮一个朋友收拾烂摊子。他们公司要把业务系统从阿里云迁到腾讯云,本来觉得数据库迁移嘛,不就是导出导入,结果数据丢了整整两天的交易记录,老板差点当场掀桌子。

这事说起来真不新鲜。数据库迁移看似是技术活,实际上是心累活。很多人一上来就想着“快”,恨不得一天搬完,结果往往是“快”字底下埋着大坑。今天我就把数据库迁移这件事掰开揉碎地说清楚,从准备到执行到验收,每一步的坑和该注意的点,咱们都聊透。
先说准备工作。这一步最容易被忽略,也最容易出事。很多人觉得数据库里的数据就是一堆表格,搬过去就行了。错了。你得先搞清楚现在的数据库是什么版本,用的是 MySQL、PostgreSQL 还是 Oracle,版本号是多少。不同版本之间的数据类型、函数、存储过程可能有差异。比如 MySQL 5.7 和 8.0,日期时间处理方式就不一样。我见过一个案例,迁移后所有时间字段都乱了,因为源库用的是 timestamp,目标库自动转成了 datetime,时区没处理好,导致所有订单的时间都偏移了 8 小时。所以,第一步是拿一张纸,把源库的版本、字符集、存储引擎、索引类型、外键约束、触发器这些信息全列出来。别偷懒,这一步扎实了,后面少掉一半坑。
接着是数据量评估。别光看数据库文件有多大,那不管用。你得看活跃数据量、日志文件大小、临时表空间大小。我见过最夸张的例子,一个电商平台的订单数据库,数据文件才 20 GB,但 binlog 堆了 200 GB,迁移时光复制日志就花了三天,因为没人提前清理过期日志。所以评估时,把数据文件、日志文件、临时文件、undo 表空间、redo 日志这些全算上。更关键的是,要知道每天的数据增长量。如果一天新增 5 GB 的数据,你迁移过程拖两天,增量数据就可能把目标库撑爆。一个简单的方法是跑一下 informationschema 里的 tablestats,看看最近一周的数据变化趋势。这一步做完,你心里才有底,知道该留多少时间窗口,准备多大的存储空间。
再来说迁移策略。常见的有三种:全量迁移、增量迁移、混合迁移。全量迁移最简单,把源库所有数据导出再导入目标库,适合数据量小、业务允许停机的场景。比如公司内部的报表数据库,几百兆数据,周末停机一天就能搬完。增量迁移麻烦点,需要持续同步源库和目标库之间的变化数据,通常用 CDC(Change Data Capture)工具,比如 Debezium、Canal、Maxwell。这些工具监控源库的 binlog 或 redo log,把变更实时复制到目标库,适合大库、不能长时间停机的场景。混合迁移就是先做一次全量,再用增量同步追上差距,是最常用的方案。具体怎么选,取决于你的停机窗口有多长。如果只有 15 分钟,那就必须用混合迁移:全量迁移用并行导入,增量迁移用 CDC 实时同步,切流时把那 15 分钟的增量数据追上去。千万别幻想“一边跑业务一边迁移”,那不叫迁移,叫自杀。
工具选型这块,我多说两句。很多人迷信官方工具,比如 AWS 的 DMS、阿里云的 DTS,觉得“云厂商推荐的肯定没问题”。但现实是,这些工具在标准场景下确实好用,一旦遇到奇葩环境——比如数据库有自定义函数、存储过程用了非标准语法、表结构里带了空间索引或全文索引——这些工具常常翻车。我见过一个项目,用 DTS 迁移一个 PostgreSQL 库,里面有个函数用了 plpythonu 扩展,DTS 直接不支持,迁移后函数全丢了。所以工具选型要实测,不能光看文档。拿一个小表做测试迁移,看看工具能否处理你的特殊场景。如果不行,就考虑用原生工具,比如 pgdump、mysqldump、Oracle 的 expdp/impdp。虽然慢,但兼容性好。另外,别忘了压缩传输。大库迁移时,网络带宽是瓶颈。用 gzip 或 lz4 压缩数据流,能省一半以上的时间。我做过测试,10 GB 的 MySQL 库,不压缩要 40 分钟,压缩后 15 分钟搞定。
执行阶段最考验细节。先把源库设为只读模式。这一步很多人忘了,结果迁移过程中业务还在写数据,导致数据不一致。设只读之前,得先通知业务方,确认没有正在执行的长事务。一个办法是跑一下 show processlist,看看有没有长时间运行的写操作。如果有,等它结束再设只读。然后开始全量导出。导出的顺序也有讲究:先导表结构,再导数据,最后导索引、触发器、存储过程。因为索引和触发器会影响导入速度。很多新手一上来就导全部,结果导入时每插一条数据都要更新索引,速度慢得令人发指。正确做法是先导表结构并在目标库创建,然后禁用索引和约束,开始导数据,数据导完再重建索引和约束,这样能快 3 到 5 倍。对于超大表,可以分片导出,按主键范围或日期范围切成多个文件并行导入。但要小心,分片粒度不能太细,否则文件数量太多,反而增加 IO 开销。一般每个文件 50‑100 万条数据比较合适。
增量同步阶段的核心是监控延迟。CDC 工具会有延迟指标,比如当前同步位置和源库最新位置之间的差距。这个延迟必须控制在秒级,最好是毫秒级。如果延迟超过 1 分钟,说明增量同步跟不上业务写入速度。此时需要检查几个点:一是源库的 binlog 格式是否为 ROW,STATEMENT 格式 CDC 工具解析不了;二是目标库的写入性能,是否因为索引太多或磁盘 IO 瓶颈;三是网络带宽,是否被其他业务占用。我们曾遇到增量同步延迟持续增长,排查半天后发现是目标库的 redo log 太小,频繁触发 checkpoint 导致写入变慢。把 redo log 调大后,延迟立刻下降。所以监控不止看延迟数值,还要关注目标库的系统和数据库指标。
切流环节最考验胆量。切流就是正式把业务从源库切换到目标库。此之前必须做两件事:全量数据校验和增量数据校验。全量校验可以在源库和目标库分别跑 count() 和 checksum,确保行数和数据一致。但 count() 对超大表很慢,可以先用 informationschema 里的行数估算值对比,再抽检关键表。增量校验比较麻烦,需要对比最近一段时间的变更。常用的方法是在源库和目标库记录一个时间戳,然后对比该时间点之后的所有变更。MySQL 可以使用 pt‑table‑checksum 自动对比主从数据一致性,其他数据库可以自行编写脚本,按主键逐条对比。校验通过后才能切流。切流步骤:先停止源库写入,确认增量同步已追上,然后把应用配置指向目标库,验证功能是否正常。这一步必须留有回滚方案。如果切流后发现数据不一致或性能问题,要能快速切回源库,所以源库至少保留 48 小时。
说到验收。很多人觉得数据校验通过就完事了,但业务方不这么看。他们关心查询速度有没有变慢、报表跑得是否仍然快、存储过程执行结果是否正确。因此验收不仅是技术验收,还要做业务验收。把业务方的核心功能列表拿过来,一条条测试,例如订单查询、用户登录、财务对账等关键路径必须跑一遍。再细化到排序、分页、模糊查询、复杂 join 等场景,看看是否有性能退化。我见过一个案例,迁移后所有 like 查询都变慢,因为源库用的是 utf8 字符集,目标库用了 utf8mb4,字符排序规则变了,索引失效。验收阶段要跑性能测试,对比迁移前后的查询响应时间。一个简单办法是把源库的慢查询日志导出,在目标库重放,看看是否出现新增慢查询。如果发现性能问题,优先检查索引、统计信息和数据库参数配置,例如 MySQL 的 innodbbufferpoolsize、maxconnections 等,很多时候默认值太小,调大就能解决。
数据库迁移说到底就是四个字:稳字当头。别想着走捷径,别迷信工具,别忽略细节。每一步都扎实了,迁移就是一次平平无奇的日常操作;但漏了任何一步,就可能演变成灾难。我那位朋友后来花了整整一周才把数据找回来,还把客户投诉的锅背上了。所以,下次做数据库迁移时,不妨把这篇拿出来,对着清单一步步过,省得半夜三点被老板电话叫起来,问你怎么把订单数据搞丢了。那滋味,真的不好受。


