数据库在线无感迁移

标签: #技术 #后端 #数据库
发布于: 2026-09-03
目录

在线无感迁移要解决三件事:业务不停机、数据不丢失、出问题能回滚。标准实现可以概括为一句话:全量迁移 + 增量同步 + 灰度切流。先分批迁走历史数据,再用 binlog 等增量同步手段补齐全量期间产生的新数据,最后把流量逐步从旧库切到新库。

常见错误:把停机迁移当成在线迁移

提到在线迁移,如果回答“先停旧库,导出数据,导入新库,改配置,重启服务”,本质是停机迁移,并不符合“在线”的要求。真正的难点不是“把数据搬过去”,而是业务还在跑、数据还在写的时候,如何保证搬迁过程对用户无感,并且一旦出问题还能回滚。

标准流程概览

一个可交付的在线迁移流程大致包括:

  1. 准备新库:建表、建索引、配权限、配监控。
  2. 开启增量同步,记录 binlog 位点。
  3. 分批执行全量迁移。
  4. 全量完成后继续回放增量日志,让新库追平旧库。
  5. 做数据校验:数量校验、分段 hash 校验、业务校验。
  6. 灰度切读,再灰度切写。
  7. 稳定运行一段时间后,下线旧库。

下面按阶段展开说明。

阶段一:全量迁移

全量迁移的目标是把旧库中的历史数据搬进新库。

  • 数据量不大时,可以直接用 mysqldump、DataX、DTS 等工具。
  • 订单表、用户表这类大表不能直接全表扫描。正确做法是按主键或时间范围分批迁移,比如每批几千条,一批一批地拉取。
  • 分批迁移必须支持限速和断点续传。否则一旦中途失败,就要从头再来,还可能把线上库压力打爆。

阶段二:增量同步与 binlog 位点

全量迁移期间,旧库仍在持续写入,因此需要监听旧库的变更日志,把新增和变更同步到新库。

  • MySQL 中核心是 binlog。常用工具包括 Canal、Debezium、Flink CDC,以及云厂商的 DTS。
  • 这些工具捕获旧库的 insert、update、delete,然后同步到新库。
  • 一个关键动作:先记录 binlog 位点,再开始全量迁移。这样全量迁移过程中产生的新数据,后续可以从这个位点继续回放,避免丢数据。

阶段三:解决全量与增量的数据回退

全量和增量两条同步链路同时存在时,会产生覆盖冲突。一个经典场景是:

  • 全量迁移时,某条订单状态还是“待支付”。
  • 用户在这期间恰好完成支付。
  • 增量同步已经将新库中的订单更新为“已支付”。
  • 如果此时全量数据再次覆盖过去,新库就会被改回“待支付”,造成数据回退。

解决办法是控制写入的幂等性。最好使用 $update_time$ 或版本号字段,让更新的数据覆盖旧数据,避免旧数据反向覆盖新数据。简单说:全量负责补历史,增量负责追最新,最终以最新变更为准

阶段四:三层数据校验

数据迁移完成后不能直接切流量,必须先做校验。只看行数远远不够,因为行数相等不代表内容一致。推荐三层校验:

  1. 数量校验:每张表的数据量是否一致。
  2. 内容校验:按主键范围做 hash 或 checksum,逐段对比。
  3. 业务校验:订单、支付单、退款单之间能否对应;用户余额、交易流水、订单状态是否一致。核心资金链路必须重点校验。

阶段五:灰度切流

切流不能一次全切,顺序是先切读、再切写。

读流量可以按比例灰度,比如先让 1% 的查询请求读新库,观察接口耗时、错误率、慢查询、连接数、主从延迟等指标,确认没问题后再逐步扩大到 10%、50%、100%。

写流量的风险远高于读流量,因为一旦切换到新库写,旧库可能就不再是最新状态。因此在切写之前,必须确认:

  • 新库已经追平旧库;
  • 索引和参数配置没有问题;
  • 监控和回滚方案都已准备好。

三种切流实现方式

  1. 配置中心切换数据源:业务服务的数据库连接不从本地配置文件写死,而是从配置中心动态读取。发布新配置即可切换请求目标。
  2. 数据库代理切换:业务连接的是代理层,由代理层决定请求实际打到旧库还是新库,上层业务无感知。
  3. 业务灰度开关:按用户 ID、租户 ID 或订单 ID 等维度分批切流。先让一小部分用户走新库,验证无问题后再逐步放量。

双写可用吗?

可以用,但不能乱用。

业务层双写最大的问题是两个库之间没有天然的分布式事务。如果写旧库成功、写新库失败,或者写新库成功、写旧库失败,都会造成数据不一致,而业务层很难自动弥补。

更推荐的做法是:

  • 迁移前期,业务只写旧库,通过 binlog 同步到新库。
  • 到切写阶段,可以短时间保留反向同步或双写,用来支持回滚。
  • 但不要长期依赖双写来做一致性保障。

易错点与限制

  • 不要把“停机迁移”包装成在线迁移。
  • 不要用全表扫描处理大表,必须分批 + 断点续传。
  • 不要先全量再记位点,位点记录必须放在全量迁移开始之前。
  • 不要只通过 count 判断数据一致,必须配合 hash/checksum 校验和业务校验。
  • 不要一次性全量切流,读流量和写流量都要灰度。
  • 不要在业务正常运行期长期使用双写,一致性将难以保证。

总结

在线无感迁移不是简单的“搬运数据”,而是一套需要同时管理“存量数据”“增量变更”“流量调度”的系统工程。整个链路的关键记忆点是:全量迁移 + 增量同步 + 灰度切流。其中,全量要分批、增量要盯位点、覆盖要防回退、校验要分三层、切流要先读后写,最后再稳定下线旧库。把这条链路讲清楚,基本就可以证明你已经理解线上数据库迁移。