半夜两点,运维老张的手机震了十七下。不是闹钟,是告警群。数据库迁移后第一个业务高峰,订单表查询直接超时,支付接口报错率飙到40%。他披上衣服冲到机房,屏幕上一排红色告警像血一样刺眼。这场景太熟悉了,过去五年他经手了六次大规模迁移,没有一次是风平浪静收场的。数据迁移这事儿,看着是技术活,其实是一场跟时间、跟风险、跟人性博弈的持久战。今天不聊那些高大上的方法论,就说说我这些年踩过的坑,以及怎么从坑里爬出来。

第一个难点:数据一致性,永远比你想象的更难保证。 你以为用个ETL工具,源库导到目标库,校验一下行数对得上就完事了?太天真了。有一次我们迁移用户积分系统,源库是Oracle,目标库是MySQL,行数一模一样,但跑完对账脚本才发现,有3.2%的用户的积分被悄悄抹掉了零头。原因是源库的number类型精度比MySQL的decimal高,转换时默认四舍五入,但业务规则要求的是截断。这种隐蔽的精度丢失,靠行数校验根本查不出来。破局的办法只有一个:别信工具,信业务。迁移前拉上业务方,把所有字段的转换规则一条条过,尤其是金额、积分、时间戳这些敏感字段,写进测试用例,用真实历史数据跑回归。我当时逼着团队写了两百多条字段级校验规则,虽然累,但上线后对账一次通过。
第二个难点:停机窗口不够用,是永恒的痛。 业务方说只能给四个小时,你算算全量数据导出要一个半小时,传输四十分钟,导入两个小时,索引重建二十五分钟,还剩五分钟做切换验证。这还没算中途网络抖一下,或者磁盘满了要清理。有次我们做核心交易库迁移,2.1TB的数据,计划六小时,结果跑了四小时的时候,目标库的redo log爆了,直接卡死。靠业务方特批延长窗口,折腾了十一个小时才完事。后来学乖了,用增量同步工具,比如OGG或者DataX的增量模式,提前一周就开始把源库的变更实时同步到目标库,迁移当天只需要处理那点增量差,窗口直接压缩到四十分钟以内。但这里有个坑:增量同步的延迟监控必须做好,一旦延迟超过五分钟,就要立刻报警,否则切换时数据差会大到无法收敛。
第三个难点:回滚策略,大多数人根本没想清楚。 很多团队觉得,反正做好了备份,出问题就切回去。可你知道回滚的代价有多大吗?有一次我们迁移客户主数据,上线后发现有字段映射错了,客户等级全乱套。决定回滚,结果发现源库已经被迁移后的新数据污染了——因为迁移过程中,有应用在双写。所谓回滚,根本回不到迁移前的状态。真正的破局之道是:迁移前必须设计好“双轨运行”期,新老系统并行跑至少两个完整的业务周期,数据双向同步,业务方在两边都能操作。这样即使新系统出问题,老系统还能顶上,而且不会丢数据。我们后来做支付系统迁移,就搞了三个月的双轨期,虽然前期投入大,但切换当天出了问题,业务方一句话“切回老系统”,三分钟搞定,零损失。
第四个难点:性能降级,上线即灾难。 数据迁过去了,功能看着也正常,但一压测就露馅。同样的SQL,在Oracle上跑20毫秒,到了PostgreSQL上变成800毫秒。为啥?索引策略、优化器行为、统计信息收集时机,全都不一样。最典型的是分页查询,MySQL的limit深翻页和SQL Server的offset分页,性能差一个数量级。我们有个报表系统迁移,上线第二天,业务方投诉月度汇总报表跑不出来,一查,一个关联了八张表的聚合查询,跑了四十分钟没出结果。后来把SQL重写,拆成三段,每段结果临时落表,再合并,总算压到三分钟以内。破局的办法就是:迁移前做全量SQL性能基线,把核心业务的所有慢查询捞出来,一条条在目标库上跑,超过阈值的全部重写。别嫌麻烦,这个功夫省不了。
第五个难点:人的问题,比技术问题更难搞。 数据库管理员用惯了老库,各种命令、工具、运维脚本全是围绕老库写的。迁到新库,DBA的第一反应是抗拒,第二反应是消极怠工。开发团队也一样,ORM框架里一堆方言,换库之后连个日期格式化都要改。我们有个项目迁完数据库,光是改代码里的SQL方言就花了两周,期间还出了一个线上事故——有个开发在代码里硬编码了老库的序列生成器,新库根本不支持。破局的关键不是逼大家学新东西,而是建一个“兼容层”。比如在目标库上做视图,模拟老库的函数和语法,让应用层改动最小化。同时,安排两到三周的“影子模式”,所有流量切一小部分过去,让团队在日常工作中熟悉新库的脾气。人一旦有了掌控感,配合度自然就上来了。
回到开头老张那次事故。后来复盘发现,真正的根因不是技术,而是决策层为了赶项目进度,砍掉了双轨运行期,要求“一刀切”切换。数据迁移从来不是搬砖,它是一个系统工程。五大难点——一致性、停机窗口、回滚策略、性能降级、人的适应——每一个都得提前布局。别指望一次迁移能顺风顺水,那是不可能的。但如果你能把这五个坑提前填平,至少半夜两点那十七个电话,能变成凌晨四点的三个未接来电。记住,迁移成功的标志不是“上线了”,而是“三个月后没人再提迁移这回事”。


