故障报错
Could not execute Write_rows event on table test.users; Duplicate entry '3' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000031, end_log_pos 329
这是由于从库存在与主库相同主键值,导致从库无法同步的报错,也是非常经典的同步报错,接下来让我们一起来实战演练一下!
一、故障模拟步骤
环境准备
- 主库:IP 10.33.112.22,MySQL 5.7
- 从库:IP 10.30.76.4,MySQL 5.7
- 同步数据库:
test
- 测试表:
users
(结构如下)
CREATE TABLE users (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(50) NOT NULL
);
1 . 模拟数据不一致故障
-
主库插入数据
-- 主库操作 INSERT INTO test.users (name) VALUES ('Alice'); INSERT INTO test.users (name) VALUES ('Bob');
-
从库手动篡改数据(模拟误操作)
-- 从库操作(跳过主从同步,直接写数据) STOP SLAVE; -- 临时停止复制 INSERT INTO test.users (id, name) VALUES (3, 'Hacker'); -- 强制插入 id=3 的数据 START SLAVE; -- 重启复制
-
主库继续写入数据
-- 主库操作 INSERT INTO test.users (name) VALUES ('Charlie'); -- 该操作生成的id=3
3. 触发主从同步错误
此时主库将生成一条 id=3
的记录,但该事件在从库重放时,因从库的 AUTO_INCREMENT
计数器未更新,会发生以下错误:
-- 从库状态检查
SHOW SLAVE STATUS\G
*************************** 1. row ***************************
Slave_IO_State: Waiting for master to send event
Master_Host: 192.168.1.100
Master_User: repl
Slave_IO_Running: Yes
Slave_SQL_Running: No -- SQL线程已停止
Last_Error: Error 'Duplicate entry '2' for key 'PRIMARY'' on query...
Last_Errno: 1062 -- 主键冲突错误
二、紧急处理办法
不推荐,可能会导致冲突的数据丢失,也就是在出库插入id=3的数据会丢失
什么是GTID
什么是GTID呢, 简而言之,就是全局事务ID(global transaction identifier ),最初由google实现,官方MySQL在5.6才加入该功能。
GTID是事务提交时创建分配的唯一标识符,所有事务均与GTID一一映射。
-
非GTID模式
SET GLOBAL sql_slave_skip_counter = 1; -- 跳过1个事件 START SLAVE;
-
GTID模式(需指定GTID_NEXT)
STOP SLAVE; SET GTID_NEXT='uuid:3'; -- 替换为SHOW SLAVE STATUS中报错的GTID BEGIN; COMMIT; -- 空事务跳过冲突GTID SET GTID_NEXT=AUTOMATIC; START SLAVE;
举例,通过show slave status\G 查看一下这行信息,那我们需要跳过的gtid就为8dcd492d-ce6b-11ef-9803-005056b388fd:36
Retrieved_Gtid_Set: 8dcd492d-ce6b-11ef-9803-005056b388fd:31-36
二、修复数据
在从库使用((20250226135629-6ufo3yl “pt-table-sync”))工具,会自动将不一样的数据做修改
主库
mysql> select * from users;
+----+---------+
| id | name |
+----+---------+
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |
从库
mysql> select * from users;
+----+--------+
| id | name |
+----+--------+
| 1 | Alice |
| 2 | Bob |
| 3 | Hacker |
+----+--------+
使用pt-table-sync修复
pt-table-sync --execute --sync-to-master h=10.30.76.4 --databases=test --tables=users --print --verbose --ask-pass
从库恢复
mysql> select * from users;
+----+---------+
| id | name |
+----+---------+
| 1 | Alice |
| 2 | Bob |
| 3 | Charlie |