数据库迁移实战
问题
需要将 MySQL 数据库从自建机房迁移到云上(或跨版本升级),要求零停机或极短停机,如何操作?
答案
迁移方案对比
| 方案 | 停机时间 | 复杂度 | 数据一致性 | 适用场景 |
|---|---|---|---|---|
| mysqldump 导入 | 长(小时级) | 低 | ✅ | 小库(< 10GB) |
| 主从复制切换 | 秒级 | 中 | ✅ | 同版本 / 跨版本 |
| DTS 数据同步 | 秒级 | 低 | ✅ | 上云迁移 |
| 双写方案 | 零停机 | 高 | ⚠️ | 异构迁移 |
方案一:基于主从复制的迁移(推荐)
# Step 1: 新库与旧库建立主从
# 在新库上执行
CHANGE MASTER TO
MASTER_HOST='old-db.example.com',
MASTER_USER='repl_user',
MASTER_PASSWORD='repl_pass',
MASTER_AUTO_POSITION=1; -- GTID 模式
START SLAVE;
# 确认复制正常
SHOW SLAVE STATUS\G
# Seconds_Behind_Master: 0 -- 追平后才能切换
# Step 2: 切换前检查
# 确认数据一致
pt-table-checksum --host=old-db --databases=mydb
# Step 3: 切换(闪断窗口 < 30 秒)
# 1. 旧库设为只读
SET GLOBAL read_only = ON;
SET GLOBAL super_read_only = ON;
# 2. 等新库追平(通常几秒)
# SHOW SLAVE STATUS → Seconds_Behind_Master = 0
# 3. 新库断开复制,设为可写
STOP SLAVE;
RESET SLAVE ALL;
SET GLOBAL read_only = OFF;
# 4. 应用连接切换到新库(修改 DNS / 配置)
# 5. 验证业务正常
方案二:停机迁移(小库简单方案)
# 适合 < 10GB 的小库
# 1. 应用停止写入
# 2. 导出
mysqldump -h old-db -u root -p \
--single-transaction \
--routines --triggers --events \
--set-gtid-purged=OFF \
mydb > mydb_backup.sql
# 3. 导入新库
mysql -h new-db -u root -p mydb < mydb_backup.sql
# 4. 切换应用连接
# 5. 验证
数据校验
# 使用 pt-table-checksum 验证数据一致性
pt-table-checksum \
--host=old-db \
--user=root \
--databases=mydb \
--replicate=percona.checksums
# 查看差异
pt-table-sync \
--print \
--replicate=percona.checksums \
--host=old-db \
--databases=mydb
# 简单校验:行数对比
mysql -h old-db -e "SELECT COUNT(*) FROM mydb.users"
mysql -h new-db -e "SELECT COUNT(*) FROM mydb.users"
迁移 Checklist
| 步骤 | 检查项 | 状态 |
|---|---|---|
| 1 | 新库版本兼容性确认 | ☐ |
| 2 | 新库参数配置与旧库对齐 | ☐ |
| 3 | 建立复制并追平 | ☐ |
| 4 | pt-table-checksum 数据校验通过 | ☐ |
| 5 | 应用连接测试新库 | ☐ |
| 6 | 回滚方案准备(新库反向复制旧库) | ☐ |
| 7 | 切换窗口通知业务方 | ☐ |
| 8 | 执行切换 | ☐ |
| 9 | 业务验证 | ☐ |
| 10 | 观察 24 小时,确认无问题后下线旧库 | ☐ |
常见面试问题
Q1: 迁移过程中如何保证可以回滚?
答案:
- 反向复制:切换前在旧库上建立对新库的复制(新主→旧从),一旦新库有问题,可以切回旧库
- 不立即下线旧库:切换后保留旧库 24~72 小时
- DNS TTL 调低:切换前将 DNS TTL 降到 60 秒,确保回切时快速生效
- 数据对账:切换后持续运行数据校验脚本