数据库在线无感迁移
目录
在线无感迁移要解决三件事:业务不停机、数据不丢失、出问题能回滚。标准实现可以概括为一句话:全量迁移 + 增量同步 + 灰度切流。先分批迁走历史数据,再用 binlog 等增量同步手段补齐全量期间产生的新数据,最后把流量逐步从旧库切到新库。
常见错误:把停机迁移当成在线迁移
提到在线迁移,如果回答“先停旧库,导出数据,导入新库,改配置,重启服务”,本质是停机迁移,并不符合“在线”的要求。真正的难点不是“把数据搬过去”,而是业务还在跑、数据还在写的时候,如何保证搬迁过程对用户无感,并且一旦出问题还能回滚。
标准流程概览
一个可交付的在线迁移流程大致包括:
- 准备新库:建表、建索引、配权限、配监控。
- 开启增量同步,记录 binlog 位点。
- 分批执行全量迁移。
- 全量完成后继续回放增量日志,让新库追平旧库。
- 做数据校验:数量校验、分段 hash 校验、业务校验。
- 灰度切读,再灰度切写。
- 稳定运行一段时间后,下线旧库。
下面按阶段展开说明。
阶段一:全量迁移
全量迁移的目标是把旧库中的历史数据搬进新库。
- 数据量不大时,可以直接用 mysqldump、DataX、DTS 等工具。
- 订单表、用户表这类大表不能直接全表扫描。正确做法是按主键或时间范围分批迁移,比如每批几千条,一批一批地拉取。
- 分批迁移必须支持限速和断点续传。否则一旦中途失败,就要从头再来,还可能把线上库压力打爆。
阶段二:增量同步与 binlog 位点
全量迁移期间,旧库仍在持续写入,因此需要监听旧库的变更日志,把新增和变更同步到新库。
- MySQL 中核心是 binlog。常用工具包括 Canal、Debezium、Flink CDC,以及云厂商的 DTS。
- 这些工具捕获旧库的 insert、update、delete,然后同步到新库。
- 一个关键动作:先记录 binlog 位点,再开始全量迁移。这样全量迁移过程中产生的新数据,后续可以从这个位点继续回放,避免丢数据。
阶段三:解决全量与增量的数据回退
全量和增量两条同步链路同时存在时,会产生覆盖冲突。一个经典场景是:
- 全量迁移时,某条订单状态还是“待支付”。
- 用户在这期间恰好完成支付。
- 增量同步已经将新库中的订单更新为“已支付”。
- 如果此时全量数据再次覆盖过去,新库就会被改回“待支付”,造成数据回退。
解决办法是控制写入的幂等性。最好使用 $update_time$ 或版本号字段,让更新的数据覆盖旧数据,避免旧数据反向覆盖新数据。简单说:全量负责补历史,增量负责追最新,最终以最新变更为准。
阶段四:三层数据校验
数据迁移完成后不能直接切流量,必须先做校验。只看行数远远不够,因为行数相等不代表内容一致。推荐三层校验:
- 数量校验:每张表的数据量是否一致。
- 内容校验:按主键范围做 hash 或 checksum,逐段对比。
- 业务校验:订单、支付单、退款单之间能否对应;用户余额、交易流水、订单状态是否一致。核心资金链路必须重点校验。
阶段五:灰度切流
切流不能一次全切,顺序是先切读、再切写。
读流量可以按比例灰度,比如先让 1% 的查询请求读新库,观察接口耗时、错误率、慢查询、连接数、主从延迟等指标,确认没问题后再逐步扩大到 10%、50%、100%。
写流量的风险远高于读流量,因为一旦切换到新库写,旧库可能就不再是最新状态。因此在切写之前,必须确认:
- 新库已经追平旧库;
- 索引和参数配置没有问题;
- 监控和回滚方案都已准备好。
三种切流实现方式
- 配置中心切换数据源:业务服务的数据库连接不从本地配置文件写死,而是从配置中心动态读取。发布新配置即可切换请求目标。
- 数据库代理切换:业务连接的是代理层,由代理层决定请求实际打到旧库还是新库,上层业务无感知。
- 业务灰度开关:按用户 ID、租户 ID 或订单 ID 等维度分批切流。先让一小部分用户走新库,验证无问题后再逐步放量。
双写可用吗?
可以用,但不能乱用。
业务层双写最大的问题是两个库之间没有天然的分布式事务。如果写旧库成功、写新库失败,或者写新库成功、写旧库失败,都会造成数据不一致,而业务层很难自动弥补。
更推荐的做法是:
- 迁移前期,业务只写旧库,通过 binlog 同步到新库。
- 到切写阶段,可以短时间保留反向同步或双写,用来支持回滚。
- 但不要长期依赖双写来做一致性保障。
易错点与限制
- 不要把“停机迁移”包装成在线迁移。
- 不要用全表扫描处理大表,必须分批 + 断点续传。
- 不要先全量再记位点,位点记录必须放在全量迁移开始之前。
- 不要只通过 count 判断数据一致,必须配合 hash/checksum 校验和业务校验。
- 不要一次性全量切流,读流量和写流量都要灰度。
- 不要在业务正常运行期长期使用双写,一致性将难以保证。
总结
在线无感迁移不是简单的“搬运数据”,而是一套需要同时管理“存量数据”“增量变更”“流量调度”的系统工程。整个链路的关键记忆点是:全量迁移 + 增量同步 + 灰度切流。其中,全量要分批、增量要盯位点、覆盖要防回退、校验要分三层、切流要先读后写,最后再稳定下线旧库。把这条链路讲清楚,基本就可以证明你已经理解线上数据库迁移。