主从复制中断的常见原因与恢复方法
概述
MySQL 主从复制在运维中是极易出问题的组件。网络波动、数据冲突、配置变更等都可能导致复制中断。了解常见的中断原因和恢复步骤,是 DBA 的核心技能。
复制中断的两种类型
I/O 线程中断
I/O 线程负责从主库拉取 Binlog,如果中断,从库不再接收新数据。
SHOW SLAVE STATUS\G
-- Slave_IO_Running: No ← I/O 线程中断
-- Slave_SQL_Running: Yes ← SQL 线程正常
-- Last_IO_Error: ... ← 错误信息
SQL 线程中断
SQL 线程负责回放 Relay Log,如果中断,数据停止同步。
SHOW SLAVE STATUS\G
-- Slave_IO_Running: Yes ← I/O 线程正常
-- Slave_SQL_Running: No ← SQL 线程中断
-- Last_SQL_Error: ... ← 错误信息
常见中断原因及恢复
1. 网络中断
症状:
Last_IO_Error: error reconnecting to master 'repl@192.168.1.10:3306' -
retry-time: 60 retries: 1, message: Can't connect to MySQL server on '192.168.1.10' (110)
原因:主库宕机、网络抖动、防火墙拦截。
恢复:
# 1. 检查网络
ping 192.168.1.10
telnet 192.168.1.10 3306
# 2. 确认主库运行正常
mysql -h 192.168.1.10 -u root -p -e "SELECT 1"
# 3. 从库上启动复制
START SLAVE;
预防:部署在同一内网、避免跨机房、配置网络监控。
2. 主键冲突
症状:
Last_SQL_Error: Error 'Duplicate entry '100' for key 'PRIMARY'' on query.
Default database: 'test'. Query: 'INSERT INTO users(id, name) VALUES(100, 'Alice')'
原因:从库上误写了数据,与主库同步过来的数据冲突。
恢复:
-- 第一步:查看冲突的具体记录
SELECT * FROM users WHERE id = 100;
-- 确认从库中已存在 id=100 的脏数据
-- 第二步:删除脏数据
DELETE FROM users WHERE id = 100;
-- 第三步:跳过该事务(不推荐永久跳过)
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;
更好的恢复方式(GTID 模式):
-- 跳过指定 GTID 的事务
-- 1. 找到冲突的 GTID
SHOW SLAVE STATUS\G
-- Executed_Gtid_Set 和 Retrieved_Gtid_Set
-- 2. 手动注入该 GTID 作为已执行
SET GTID_NEXT = '3e11fa47-61ca-11e8-9e70-00163e114761:123';
BEGIN; COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START SLAVE;
预防:从库必须设置 read_only = ON,防止误写。
3. 从库事务比主库大
症状:
Last_SQL_Error: Could not execute Write_rows event on table test.orders;
Duplicate entry '5000' for key 'PRIMARY', Error_code: 1062;
handler error HA_ERR_KEY_NOT_FOUND;
原因:从库上执行了大事务的 INSERT…SELECT,或者从库自增值超前。
恢复:
-- 方法 1:手动处理冲突后跳过
SET GLOBAL sql_slave_skip_counter = 1;
-- 方法 2:GTID 模式下跳过
SHOW SLAVE STATUS\G
-- 获取 Last_Executed_Transaction
SET GTID_NEXT = '<冲突事务的 GTID>';
BEGIN; COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START SLAVE;
4. 主库 Binlog 被清理
症状:
Last_IO_Error: Got fatal error 1236 from master when reading data
from binary log: 'The slave is connecting using CHANGE MASTER TO
MASTER_AUTO_POSITION = 1, but the master has a purged binary log
containing the GTIDs that the slave requires.'
原因:主库清理了 Binlog,从库需要的 Binlog 已经不存在了。
恢复:
-- 方法 1:从最新位置重新同步(会丢失部分数据)
STOP SLAVE;
CHANGE MASTER TO MASTER_AUTO_POSITION = 0,
MASTER_LOG_FILE = 'mysql-bin.000045', -- 主库当前最新的 Binlog
MASTER_LOG_POS = 4; -- 从头开始
START SLAVE;
-- 方法 2:重新搭建从库(数据安全)
-- 1. 主库导出数据
-- mysqldump --all-databases --master-data=2 > dump.sql
-- 2. 从库导入
-- mysql < dump.sql
-- 3. 设置新的同步点
预防:设置合理的 Binlog 过期时间,监控从库延迟:
binlog_expire_logs_seconds = 604800 -- 保留 7 天
5. 表结构不一致
症状:
Last_SQL_Error: Error 'Unknown column 'email' in 'field list'' on query.
Query: 'ALTER TABLE users ADD COLUMN email VARCHAR(100)'
-- 或者
Last_SQL_Error: Error 'Can't find file: './test/users' (errno: 2)'
原因:主库和从库的表结构不同(手动在其中一个改了)。
恢复:
-- 1. 比较主从表结构
SHOW CREATE TABLE users; -- 主库和从库分别查看
-- 2. 在从库上执行 ALTER 使结构一致
ALTER TABLE users ADD COLUMN email VARCHAR(100); -- 如果从库缺少
-- 3. 启动复制
START SLAVE;
中断恢复流程
发现复制中断(监控告警)
│
├── 查看 SHOW SLAVE STATUS
│
├── Slave_IO_Running: No
│ ├── 检查网络(ping + telnet)
│ ├── 检查主库是否运行
│ ├── 检查 Binlog 是否被清理
│ └── START SLAVE
│
└── Slave_SQL_Running: No
├── 查看 Last_SQL_Error
├── 检查数据是否冲突
├── 处理冲突(删除/更新数据)
├── 跳过事务(sql_slave_skip_counter 或 GTID 注入)
└── START SLAVE
恢复后的验证
-- 1. 检查复制状态
SHOW SLAVE STATUS\G
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: Yes
-- 2. 验证延迟在减小
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master: 减少趋势 ✅
-- 3. 检查数据一致性
-- 对比主从的关键表行数
SELECT COUNT(*) FROM users; -- 主库和从库分别执行
面试要点
- 最常见的中断原因:主键冲突(从库误写)、网络中断、Binlog 被清理
- 两类线程中断:I/O 线程(拉取问题)和 SQL 线程(回放问题)
- 恢复通用步骤:看错误信息 → 解决根本原因 →
START SLAVE - 从库必须设置
read_only=ON,防止误写导致复制中断 - GTID 模式恢复更友好:可以通过 GTID 定向跳过特定事务
- 预防胜于恢复:合理配置 Binlog 保留、监控延迟、从库只读
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END


暂无评论内容