数据库跨服务器迁移完整方案:MySQL零停机迁移、主从同步与数据验证实战
数据库迁移是最风险的运维操作之一——一旦出错可能导致数据丢失或业务长时间中断。本文提供两套方案:适合小型数据库的快速迁移方案,以及适合大型生产数据库的零停机迁移方案。
一、迁移前评估
# 评估数据库大小
mysql -u root -p -e "
SELECT table_schema AS '数据库',
ROUND(SUM(data_length + index_length) / 1024 / 1024, 2) AS '大小(MB)'
FROM information_schema.tables
GROUP BY table_schema
ORDER BY SUM(data_length + index_length) DESC;"
# 评估表数量和最大表
mysql -u root -p -e "
SELECT table_schema, table_name,
ROUND((data_length + index_length) / 1024 / 1024, 2) AS size_mb
FROM information_schema.tables
ORDER BY size_mb DESC LIMIT 20;"
# 查看当前连接数和活跃事务
mysql -u root -p -e "SHOW PROCESSLIST;"
mysql -u root -p -e "SHOW ENGINE INNODB STATUS\G" | grep -A5 "TRANSACTIONS"二、方案A:快速迁移(停机时间约5~30分钟)
适用于数据库大小在10GB以内,业务可以接受短暂停机的场景。
<code">#!/bin/bash
# /usr/local/bin/db-migrate-quick.sh
OLD_DB_HOST="旧服务器IP"
NEW_DB_HOST="新服务器IP"
DB_USER="root"
DB_PASS="数据库密码"
BACKUP_FILE="/tmp/full_backup_$(date +%Y%m%d_%H%M%S).sql.gz"
echo "=== 步骤1:停止写入(通知应用层暂停) ==="
# 在应用服务器上:停止Nginx/PHP-FPM 或 切换维护页
# systemctl stop nginx
echo "=== 步骤2:在旧服务器上导出数据库 ==="
mysqldump -h "$OLD_DB_HOST" -u "$DB_USER" -p"$DB_PASS" \
--all-databases \
--single-transaction \
--master-data=2 \
--flush-logs \
--routines \
--triggers \
--events \
| gzip > "$BACKUP_FILE"
echo "备份完成,大小:$(du -sh $BACKUP_FILE)"
echo "=== 步骤3:传输到新服务器 ==="
scp "$BACKUP_FILE" root@"$NEW_DB_HOST":/tmp/
echo "=== 步骤4:在新服务器上恢复 ==="
ssh root@"$NEW_DB_HOST" "
gunzip < $BACKUP_FILE | mysql -u $DB_USER -p'$DB_PASS'
echo '恢复完成'
"
echo "=== 步骤5:更新应用配置,指向新数据库 ==="
# 修改 wp-config.php 或应用配置文件的 DB_HOST
echo "=== 步骤6:恢复服务 ==="
# systemctl start nginx三、方案B:零停机迁移(基于主从复制)
适用于大型数据库或无法接受停机的生产环境。核心思路:先建立主从同步,待新服务器数据完全同步后,再切换应用连接。
阶段1:配置旧服务器为主节点
<code"># 在旧服务器(主节点)的MySQL配置中添加: # /etc/mysql/mysql.conf.d/mysqld.cnf [mysqld] server-id = 1 log_bin = /var/log/mysql/mysql-bin.log binlog_format = ROW binlog_do_db = 需要同步的数据库名 # 不填则同步所有库
<code">-- 创建专用复制账号 CREATE USER 'replica'@'新服务器IP' IDENTIFIED BY '复制账号密码'; GRANT REPLICATION SLAVE ON *.* TO 'replica'@'新服务器IP'; FLUSH PRIVILEGES; -- 获取当前二进制日志位置(用于配置从节点) FLUSH TABLES WITH READ LOCK; SHOW MASTER STATUS; -- 记录 File 和 Position 的值,例如: -- File: mysql-bin.000123 -- Position: 456789 UNLOCK TABLES;
阶段2:初始化新服务器并建立同步
<code">-- 在新服务器上导入初始数据后,配置从节点
CHANGE MASTER TO
MASTER_HOST='旧服务器IP',
MASTER_USER='replica',
MASTER_PASSWORD='复制账号密码',
MASTER_LOG_FILE='mysql-bin.000123', -- 上面记录的File
MASTER_LOG_POS=456789; -- 上面记录的Position
START SLAVE;
-- 验证同步状态(两个Yes表示正常)
SHOW SLAVE STATUS\G
-- 关键字段:
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- Seconds_Behind_Master: 0 ← 0表示已追上主节点,无延迟阶段3:等待完全同步后切换
<code">-- 监控同步延迟,等待降为0 -- 在新服务器上持续查看: SHOW SLAVE STATUS\G | grep "Seconds_Behind_Master" -- 切换时刻(Seconds_Behind_Master = 0时执行): -- 1. 在旧服务器暂停写入(停止应用或锁表) FLUSH TABLES WITH READ LOCK; -- 2. 等待新服务器同步完毕 -- 新服务器:SHOW SLAVE STATUS\G 确认 Seconds_Behind_Master = 0 -- 3. 停止从节点复制 -- 在新服务器执行: STOP SLAVE; RESET SLAVE ALL; -- 清除复制配置,新服务器变为独立主节点 -- 4. 更新应用配置,将DB_HOST改为新服务器IP -- 5. 解锁旧服务器 UNLOCK TABLES;
四、数据一致性验证
<code">#!/bin/bash
# 迁移后验证数据一致性
OLD="旧服务器IP"
NEW="新服务器IP"
USER="root"
PASS="密码"
echo "=== 对比各数据库的表数量 ==="
mysql -h "$OLD" -u "$USER" -p"$PASS" -e "
SELECT table_schema, COUNT(*) as tables
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema','performance_schema','sys','mysql')
GROUP BY table_schema;" > /tmp/old_tables.txt
mysql -h "$NEW" -u "$USER" -p"$PASS" -e "
SELECT table_schema, COUNT(*) as tables
FROM information_schema.tables
WHERE table_schema NOT IN ('information_schema','performance_schema','sys','mysql')
GROUP BY table_schema;" > /tmp/new_tables.txt
diff /tmp/old_tables.txt /tmp/new_tables.txt && echo "✅ 表数量一致" || echo "❌ 表数量不一致"
echo "=== 对比关键表的行数 ==="
for DB in wordpress shop; do
for TABLE in posts users options; do
OLD_COUNT=$(mysql -h "$OLD" -u "$USER" -p"$PASS" -se "SELECT COUNT(*) FROM $DB.$TABLE 2>/dev/null")
NEW_COUNT=$(mysql -h "$NEW" -u "$USER" -p"$PASS" -se "SELECT COUNT(*) FROM $DB.$TABLE 2>/dev/null")
if [ "$OLD_COUNT" = "$NEW_COUNT" ]; then
echo "✅ $DB.$TABLE: $OLD_COUNT 行"
else
echo "❌ $DB.$TABLE: 旧=$OLD_COUNT 新=$NEW_COUNT 不一致!"
fi
done
done五、应用层配置更新
<code"># WordPress配置更新
sed -i "s/define('DB_HOST', '旧服务器IP')/define('DB_HOST', '新服务器IP')/" /var/www/html/wp-config.php
# 验证连接
wp db check --allow-root
# 清除WordPress缓存
wp cache flush --allow-root
wp rewrite flush --allow-root六、迁移后监控
<code"># 迁移后24小时内持续监控: # 1. 错误日志 tail -f /var/log/mysql/error.log # 2. 慢查询(确认索引在新服务器上同样生效) tail -f /var/log/mysql/slow.log # 3. 应用错误(PHP日志) tail -f /var/log/php/error.log # 4. 监控新服务器负载 htop watch -n 5 'mysql -u root -p密码 -e "SHOW PROCESSLIST;"'
七、总结
小型数据库(10GB以内)选方案A,停机迁移简单可靠;大型生产数据库选方案B,基于主从复制实现零停机切换。迁移后必须进行数据一致性验证,保留旧服务器运行24~48小时作为应急回退选项。IDC.Net的香港VPS同账号多台服务器支持内网互通,主从同步流量走内网,速度快且不占用公网带宽配额。
版权声明:
作者:后浪云
链接:https://idc.net/help/442796/
文章版权归作者所有,未经允许请勿转载。
THE END
