数据库迁移、切割checklist

数据库迁移与切库 Checklist:我如何降低一次迁移的风险

数据库迁移不是简单修改连接串,应该把它当成一次有阶段、有验证、有回滚的工程操作:先同步数据,再切读流量,最后切写流量,并在旧库下线前完成连接核查和数据归档。

背景

我在做数据库迁移时,最担心的不是“切不过去”,而是“切过去以后才发现问题”:数据不一致、SQL 变慢、同步延迟超标、还有系统偷偷连着旧库。

所以我不会把数据库迁移设计成一次性动作。更稳妥的方式是把风险拆开:先让新库具备完整数据,再让新库承担读流量,最后再把写流量切过去。每个阶段都有明确的验证标准,出问题时也更容易回退。

整体流程可以概括为:

flowchart LR A[旧库承担读写] --> B[新库初始化] B --> C[存量导入与增量同步] C --> D[读流量切到新库] D --> E[写流量切到新库] E --> F[旧库连接核查] F --> G[归档与下线]

一、迁移前先定边界

开始导数据之前,我会先确认迁移范围。这个步骤看起来慢,但能避免后面反复补洞。

我通常会列清楚这些内容:

项目 需要确认的内容
系统范围 哪些应用、任务、报表、脚本访问旧库
表范围 哪些表迁移,哪些表保留,哪些表只读
接口范围 哪些接口读库,哪些接口写库,哪些接口读写混合
数据范围 是否全量迁移,历史数据是否归档,是否有过滤规则
时间窗口 是否允许短暂停写,是否有业务低峰期
回滚条件 读切换如何回滚,写切换后是否还能回滚

我还会提前定义成功标准,而不是只写“迁移完成”。比如:

  • 新旧库核心表行数一致,差异可解释。
  • 关键业务字段校验通过。
  • 增量同步延迟低于业务阈值。
  • 新库核心 SQL 延迟不高于迁移前基线。
  • 切换后接口错误率没有明显升高。
  • 旧库连接数逐步归零。

这些标准越具体,切换当天的判断就越少依赖感觉。

二、新库初始化与增量同步

第一个正式阶段,是让新库先拥有完整数据。此时旧库仍然承担读写,新库只负责接收历史数据和增量变更。

存量数据可以通过备份恢复、导出导入、同步工具等方式完成。大表我一般会按主键范围或时间分片迁移,避免一次性全表扫描影响旧库。

存量导入完成后,还要接上增量同步。不同数据库有不同方案,例如 MySQL 可以基于 binlog,Oracle 可以使用 OGG,PostgreSQL 可以基于 logical replication 或 WAL 解析。方案本身不是重点,关键是要确认同步链路是否具备这些能力:

  • 支持断点续传。
  • 支持失败重试。
  • 重复事件可以幂等处理。
  • 删除、更新、乱序事件处理符合预期。
  • 同步延迟可监控、可告警。

数据校验我一般分三层做:

层级 校验方式 目的
粗粒度 表行数、分区行数 发现明显漏数
中粒度 checksum、关键字段聚合 发现批量差异
细粒度 抽样业务对账 发现业务语义差异

checksum 不能替代业务对账。订单金额、账户余额、库存状态这类数据,最终还是要按业务口径再核一次。

在进入下一阶段前,我会要求存量导入完成、增量同步稳定、核心表校验通过,并确认新库的表结构、索引、容量和权限都已经检查过。

三、先切读流量

我习惯先切读,再切写。原因很简单:读流量通常更容易回滚,而且能提前暴露新库的查询性能、索引缺失和同步延迟问题。

切读之前,应用层最好具备读路由能力,至少可以通过配置控制读请求走旧库还是新库。灰度比例不要一步到位,可以从小流量开始,例如 1%、5%、10%、30%,观察稳定后再扩大。

这一阶段最容易忽略的是“读己之写”。如果旧库仍然承接写入,新库承担读取,那么用户刚写完数据后立刻查询,可能因为同步延迟读不到最新结果。对强一致场景,我会让写后短时间内继续读旧库;对后台查询或报表类场景,可以接受最终一致,但必须监控同步延迟。

切读期间我重点看这些指标:

  • 新库 QPS、连接数、CPU、IO、内存。
  • 慢 SQL 数量和接口延迟。
  • 接口错误率、超时率。
  • 新旧库查询结果差异。
  • 增量同步延迟。
  • 旧库读流量是否按预期下降。

只有当读流量稳定、新库性能达标、没有不可解释的数据差异时,我才会考虑进入写切换。

四、再切写流量

写切换是风险最高的一步。因为新库开始承接写入后,数据主权就变了,回滚成本会明显增加。

如果业务允许,我更倾向使用短暂停写窗口:先停止旧库写入,等待增量同步追平,再做最后一次数据校验,然后把写连接切到新库。这个方式虽然需要窗口,但链路清晰,风险可控。

如果业务不允许停写,就需要双写或补偿方案。但我不会轻易把“双写”当成默认答案,因为它会引入重复写、部分成功、顺序错乱、冲突处理等新问题。只要使用双写或 CDC 回放,就必须提前设计幂等策略,确保失败重试不会造成多写或脏写。

切写完成后,我不会马上下线旧库,而是保留观察窗口。观察重点包括:

  • 新库写入错误率。
  • 主键冲突、唯一键冲突。
  • 事务失败、锁等待、慢 SQL。
  • 旧库是否还有非预期写入。
  • 核心业务对账是否正常。

回滚方案必须在切写前写清楚。读切换通常可以直接切回旧库;写切换后如果已经产生新数据,回滚就可能需要停写、对账、反向修复,再恢复旧库入口。没有回滚方案,我不会贸然切写。

五、旧库核查与下线

切库完成不等于迁移结束。很多问题都出现在“以为已经没人用旧库”的时候。

旧库下线前,我会重点核查这些连接来源:

  • 业务应用是否仍连接旧库。
  • 定时任务是否仍访问旧库。
  • 报表、BI、导出脚本是否仍依赖旧库。
  • 运维脚本或临时脚本是否写死旧库地址。
  • 第三方系统是否还有旧库账号。

确认没有非预期连接后,我会把旧库先冻结为只读,再做完整备份和恢复验证。只有在业务、研发、运维、数据库负责人都确认后,才进入最终归档和下线流程。

我的简化 Checklist

迁移前

同步阶段

切换阶段

下线阶段

总结

我理解的数据库迁移,本质不是搬数据,而是控制变化。

一套可靠的迁移流程,至少要做到三点:第一,每个阶段都有明确的入口和出口标准;第二,关键风险都有监控指标和告警;第三,每次切换前都知道失败后怎么退。

只要把同步、校验、灰度、回滚和旧库下线这些环节设计清楚,数据库迁移就不再依赖临场经验,而可以变成一套可演练、可复用、可持续改进的工程流程。

posted @ 2025-05-19 14:36  鱼007  阅读(42)  评论(0)    收藏  举报