🗄️ 数据库迁移实战:不停机迁移方案、数据一致性保障与工具选型全解析 从一个凌晨 3 点的故障说起 某电商平台的订单表 orders 有 2.3 亿行数据,运行在 MySQL 5.7 上,单表体积接近 400GB。团队计划将这张表迁移到 TiDB 分布式数据库,以应对即将到来的双十一流量峰值。
DBA 团队的迁移方案是:
凌晨 2 点,停止所有写入服务 用 mysqldump 导出全量数据(耗时 1 小时 20 分钟) 将 dump 文件导入 TiDB(耗时 3 小时) 凌晨 6 点 20 分,恢复写入服务 结果:凌晨 4 点 30 分,dump 文件导入到一半时报错——导出文件中有 3 行数据包含 MySQL 5.7 特有的 utf8mb4_general_ci 排序规则下的隐藏字符,TiDB 解析失败。此时 MySQL 5.7 已被设置为只读,TiDB 导入中断, 整个订单系统处于不可用状态 。
最终临时回滚 MySQL 只读限制,恢复业务。迁移失败,双十一扩容计划延期。
这次故障暴露了数据库迁移中的核心难题:如何在保证数据一致性的前提下,尽可能缩短甚至消除停机时间,并且始终保留可靠的回滚路径。
数据库迁移策略总览 数据库迁移不是单一操作,而是一整套工程方法论。先通过思维导图建立全局认知:
flowchart LR classDef root fill:#0f172a,stroke:#3b82f6,stroke-width:2px,color:#bfdbfe,font-weight:bold; classDef branch fill:#2d1a05,stroke:#f59e0b,stroke-width:2px,color:#fde68a,font-weight:bold; classDef leaf fill:#1e1e24,stroke:#6b7280,stroke-width:1.5px,color:#e5e7eb; classDef highlight fill:#450a0a,stroke:#dc2626,stroke-width:1.5px,color:#fecaca,font-weight:bold; ROOT[数据库迁移策略体系] ROOT --> B1(1. 按停机时间分类) B1 --> L1["🛑 停机迁移\n• 停服→导出→导入→恢复\n• 停机: 小时至天级\n• 风险: 业务中断"] B1 --> L2["⚡ 零停机迁移\n• 双写/CDC/灰度切换\n• 停机: 秒级切换\n• 风险: 数据不一致"] B1 --> L3["🔄 滚动迁移\n• 按分片/租户逐批切\n• 停机: 每批秒级\n• 风险: 跨片依赖"] ROOT --> B2(2. 按数据同步方式分类) B2 --> L4["📦 全量+增量\n• 全量快照 + binlog 追赶\n• 代表: DTS/Canal/Debezium"] B2 --> L5["✍️ 双写\n• 应用层同时写新旧库\n• 全量回溯 + 双写 + 校验"] B2 --> L6["🔁 主从复制\n• 新库作为旧库的从库\n• 追平后切换"] ROOT --> B3(3. 按迁移目标分类) B3 --> L7["🏗️ 同构迁移\n• MySQL→MySQL 版本升级\n• 工具: gh-ost/pt-osc"] B3 --> L8["🔀 异构迁移\n• MySQL→TiDB/PostgreSQL\n• 需处理类型/SQL差异"] B3 --> L9["☁️ 上云迁移\n• 自建→RDS/云原生DB\n• 工具: DTS/DataX"] class ROOT root; class B1,B2,B3 branch; class L1,L2,L3,L4,L5,L6,L7,L8,L9 leaf; class L2,L4 highlight; 三类策略并非互斥——零停机迁移通常是"双写 + 全量快照 + 增量追赶 + 灰度切换"的组合。
...