数据迁移基础
数据迁移,说白了就是把数据从一个地方搬到另一个地方。
听起来简单吧?但真正做过的人都知道,这里面坑不少。我刚开始做第一个迁移项目时,以为就是个复制粘贴的活儿,结果线上跑了三天三夜,最后发现校验对不上——那叫一个头大。
所以这一节,咱们先打好基础。把概念、类型、流程理清楚,后面再聊校验就顺了。
什么是数据迁移?
数据迁移是指将数据从源系统(或存储)整体或部分地转移到目标系统的过程。目标系统可能是新数据库、新文件系统、新云服务,甚至只是换个版本。
我个人的习惯是,把迁移分成两类情况:
- 同构迁移:源和目标类型一样,比如 MySQL 5.7 → MySQL 8.0。
- 异构迁移:类型不同,比如 Oracle → PostgreSQL。这种挑战更大,因为数据类型、约束、索引都得重新映射。
一个小技巧:不管同构还是异构,先在预发环境跑一次完整迁移。我曾经跳过这一步,结果生产上遇到字符集乱码,回滚花了整晚。
两种核心迁移类型:全量 vs 增量
这就取决于你能停多长时间的业务了。咱们来对比一下。
| 维度 | 全量迁移 | 增量迁移 |
|---|---|---|
| 数据范围 | 一次性迁移所有数据 | 只迁移变化的数据(新增/修改/删除) |
| 执行时间 | 取决于数据总量,通常较长 | 轻量,可持续运行 |
| 业务停机 | 一般需要业务窗口 | 可做到近乎零停机 |
| 一致性校验 | 迁移后整体校验一次 | 需要持续校验,保证增量不丢失 |
| 常见场景 | 初次上云、版本大升级 | 实时同步、灾备 |
我见过很多团队一上来就想做增量迁移,觉得不停机很酷。但你没想清楚,增量迁移的前提是全量基准必须正确。否则增量数据叠在错误的基础上,后面校验永远对不上。
核心原则:全量打底,增量补漏。 先跑一次全量,校验通过再开增量通道。
迁移流程长什么样?
这里我总结一个通用流程,后面每一章都会回头参考它。
- 评估与规划:梳理源数据结构、数据量、表关系、业务停机容忍度。
- 全量导出:从源系统导出完整数据集,尽量保证导出时数据一致(比如用快照或读锁)。
- 全量导入:把数据写入目标系统,注意字段映射、类型转换、索引重建。
- 全量校验:对比源和目标的行数、散列值或关键字段,确保无遗漏。
- 增量捕获:开启变更数据捕获(CDC)或日志解析,记录全量导出后的所有变更。
- 增量同步:将变更持续应用到目标系统,顺序不能乱。
- 增量校验:周期性或按事件触发,校验增量部分是否完整一致。
- 切换与收尾:验证无误后,切换读写流量到目标,清理临时数据。
你想想看,这八步里,校验步骤出现了两次(全量校验和增量校验)。为什么?因为迁移最怕的就是:数据丢了、多了、错了,而你自己不知道。
我曾经踩过的坑:有一次做全量迁移,我把校验只放在最后一步,结果中途网络闪断导致某张表只导入了80%的数据,直到业务报错才发现。从那以后,我每张表导入完都立刻做一次简单校验(至少对比行数和主键最大值)。
一个简单的代码思路
这里不贴完整代码,给你一个校验行数的伪代码片段。你感受一下。
def full_validate(source_conn, target_conn, tables):
for table in tables:
src_count = source_conn.query(f"SELECT COUNT(*) FROM {table}")
tgt_count = target_conn.query(f"SELECT COUNT(*) FROM {table}")
if src_count != tgt_count:
raise Exception(f"表 {table} 行数不一致: 源 {src_count} 目标 {tgt_count}")
print("全量校验通过")
这行代码简单吧?但实际项目里我见过好多团队连这个都不写,就敢上线。
本章核心逻辑图
下面这张图把全量、增量和校验的关系画在一起,你一看就明白。