您现在的位置是:首页 > 文章详情

mysqldump 搭建复制报错,竟然是因为这个!

日期:2023-07-25点击:470

作者详细分析了一个 mysqldump 搭建复制失败的问题分析过程和改进建议。

作者:李富强

爱可生 DBA 团队成员,熟悉 MySQL,TiDB,OceanBase 等数据库。相信持续把对的事情做好一点,会有不一样的收获。

本文来源:原创投稿

  • 爱可生开源社区出品,原创内容未经授权不得随意使用,转载请联系小编并注明来源。

故障现象

某客户反馈,使用 mysqldump 搭建从库,启动复制后,复制报错:Could not execute Write_rows event on table xxx; Duplicate entry 'xxx' for key 'PRIMARY'

客户使用的命令(看起来没啥问题)。

-- 主库备份 shell> mysqldump -uroot -pxxx --master-data=2 --single-transaction -A --routines --events --triggers >/tmp/xxx.sql -- 从服务器还原备份并启动复制 mysql>reset master; mysql>reset slave all; mysql>source /tmp/xxx.sql ; mysql>change master to master_host='xxx',master_port=3306,master_user='xxx',master_password='xxx',master_auto_position=1; mysql>start slave; 

问题排查

查看复制报错表的表结构,发现表的存储引擎为 MyISAM 引擎。根据客户反馈,表访问比较频繁,mysqldump --single-transaction 选项,只能保证 InnoDB 引擎表备份的一致性,无法保证 MyISAM 引擎表备份的一致性,问题可能就出在这。

问题解决

修改表的存储引擎为 InnoDB 后,重新备份恢复,可以正常搭建从库。

问题复现

下面我们来复现一下该问题。

环境信息

操作系统 CentOS Linux release 7.5.1804 (Core)
版本 MySQL 5.7.25
主库 10.186.60.187
从库 10.186.60.37
主从 开启 GTID

操作步骤

在主库,使用 Sysbench 造一张 1000w 数据的 InnoDB 引擎的表 testdb_innodb.sbtest1(造 1000w 数据主要目的是让备份 InnoDB 引擎表的时间拉长)。

shell> sysbench /usr/share/sysbench/tests/include/oltp_legacy/oltp.lua \ --mysql-host=10.186.60.187 --mysql-port=3307 --mysql-user=root \ --mysql-password=1 --mysql-db=testdb_innodb --oltp-table-size=10000000 --oltp-tables-count=1 --threads=4 --report-interval=3 prepare -- 表结构如下 mysql> show create table testdb_innodb.sbtest1; CREATE TABLE `sbtest1` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `k` int(10) unsigned NOT NULL DEFAULT '0', `c` char(120) COLLATE utf8mb4_bin NOT NULL DEFAULT '', `pad` char(60) COLLATE utf8mb4_bin NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=InnoDB AUTO_INCREMENT=10000001 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin -- 表总行数如下: mysql> select count(*) from testdb_innodb.sbtest1; +----------+ | count(*) | +----------+ | 10000000 | +----------+ 

在主库,造一张 MyISAM 引擎的表 testdb_myisam.sbtest2

-- 表结构如下: mysql> CREATE TABLE testdb_myisam.`sbtest2` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `k` int(10) unsigned NOT NULL DEFAULT '0', `c` char(120) COLLATE utf8mb4_bin NOT NULL DEFAULT '', `pad` char(60) COLLATE utf8mb4_bin NOT NULL DEFAULT '', PRIMARY KEY (`id`), KEY `k_1` (`k`) ) ENGINE=myisam AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin 

在主库,开始 mysqldump 逻辑备份,并在执行备份 testdb_innodb.sbtest1 期间(备份的顺序:先备份 testdb_innodb 库),往 testdb_myisam.sbtest2 表插入一条数据。

-- 执行 mysqldump 备份 shell> /data/mysql/base/5.7.25/bin/mysqldump -h10.186.60.187 -P3307 -uroot -p1 --master-data=2 --single-transaction -A --routines --events --triggers >/tmp/dump.sql -- 执行备份 testdb_innodb.sbtest1 期间,往 testdb_myisam.sbtest2 表插入一条数据 mysql> insert into testdb_myisam.`sbtest2`(k,c,pad) values(2,'myisam','myisam'); -- 通过 MySQL general_log 观察备份情况 2023-07-11T16:15:50.900581+08:00 2692 Connect root@10.186.60.187 on using TCP/IP 2023-07-11T16:15:50.901124+08:00 2692 Query /*!40100 SET @@SQL_MODE='' */ 2023-07-11T16:15:50.901529+08:00 2692 Query /*!40103 SET TIME_ZONE='+00:00' */ 2023-07-11T16:15:50.901743+08:00 2692 Query FLUSH /*!40101 LOCAL */ TABLES 2023-07-11T16:15:50.938083+08:00 2692 Query FLUSH TABLES WITH READ LOCK 2023-07-11T16:15:50.938281+08:00 2692 Query SET SESSION TRANSACTION ISOLATION LEVEL REPEATABLE READ 2023-07-11T16:15:50.938410+08:00 2692 Query START TRANSACTION /*!40100 WITH CONSISTENT SNAPSHOT */ 2023-07-11T16:15:50.938678+08:00 2692 Query SHOW VARIABLES LIKE 'gtid\_mode' 2023-07-11T16:15:50.980335+08:00 2692 Query SELECT @@GLOBAL.GTID_EXECUTED 2023-07-11T16:15:50.980566+08:00 2692 Query SHOW MASTER STATUS 2023-07-11T16:15:50.980758+08:00 2692 Query UNLOCK TABLES ...略 2023-07-11T16:15:51.541911+08:00 2692 Init DB testdb_innodb 2023-07-11T16:15:51.542012+08:00 2692 Query SHOW CREATE DATABASE IF NOT EXISTS `testdb_innodb` 2023-07-11T16:15:51.542139+08:00 2692 Query SAVEPOINT sp 2023-07-11T16:15:51.542224+08:00 2692 Query show tables 2023-07-11T16:15:51.542405+08:00 2692 Query show table status like 'sbtest1' 2023-07-11T16:15:51.543353+08:00 2692 Query SET SQL_QUOTE_SHOW_CREATE=1 2023-07-11T16:15:51.543467+08:00 2692 Query SET SESSION character_set_results = 'binary' 2023-07-11T16:15:51.543548+08:00 2692 Query show create table `sbtest1` 2023-07-11T16:15:51.543729+08:00 2692 Query SET SESSION character_set_results = 'utf8' 2023-07-11T16:15:51.543837+08:00 2692 Query show fields from `sbtest1` 2023-07-11T16:15:51.544172+08:00 2692 Query show fields from `sbtest1` 2023-07-11T16:15:51.544477+08:00 2692 Query SELECT /*!40001 SQL_NO_CACHE */ * FROM `sbtest1` 2023-07-11T16:15:57.603435+08:00 2683 Query insert into testdb_myisam.`sbtest2`(k,c,pad) values(2,'myisam','myisam') 2023-07-11T16:16:27.456357+08:00 2692 Query SET SESSION character_set_results = 'binary' 2023-07-11T16:16:27.471239+08:00 2692 Query use `testdb_innodb` 2023-07-11T16:16:27.471589+08:00 2692 Query select @@collation_database 2023-07-11T16:16:27.472065+08:00 2692 Query SHOW TRIGGERS LIKE 'sbtest1' 2023-07-11T16:16:27.506025+08:00 2692 Query SET SESSION character_set_results = 'utf8' 2023-07-11T16:16:27.506225+08:00 2692 Query ROLLBACK TO SAVEPOINT sp 2023-07-11T16:16:27.506383+08:00 2692 Query RELEASE SAVEPOINT sp 2023-07-11T16:16:27.506538+08:00 2692 Query show events 2023-07-11T16:16:27.507226+08:00 2692 Query use `testdb_innodb` 2023-07-11T16:16:27.507346+08:00 2692 Query select @@collation_database 2023-07-11T16:16:27.507457+08:00 2692 Query SET SESSION character_set_results = 'binary' 2023-07-11T16:16:27.507629+08:00 2692 Query SHOW FUNCTION STATUS WHERE Db = 'testdb_innodb' 2023-07-11T16:16:27.621194+08:00 2692 Query SHOW PROCEDURE STATUS WHERE Db = 'testdb_innodb' 2023-07-11T16:16:27.622726+08:00 2692 Query SET SESSION character_set_results = 'utf8' 2023-07-11T16:16:27.622900+08:00 2692 Init DB testdb_myisam 2023-07-11T16:16:27.623005+08:00 2692 Query SHOW CREATE DATABASE IF NOT EXISTS `testdb_myisam` 2023-07-11T16:16:27.623102+08:00 2692 Query SAVEPOINT sp 2023-07-11T16:16:27.623211+08:00 2692 Query show tables 2023-07-11T16:16:27.623566+08:00 2692 Query show table status like 'sbtest2' 2023-07-11T16:16:27.624197+08:00 2692 Query SET SQL_QUOTE_SHOW_CREATE=1 2023-07-11T16:16:27.624314+08:00 2692 Query SET SESSION character_set_results = 'binary' 2023-07-11T16:16:27.624401+08:00 2692 Query show create table `sbtest2` 2023-07-11T16:16:27.624518+08:00 2692 Query SET SESSION character_set_results = 'utf8' 2023-07-11T16:16:27.624605+08:00 2692 Query show fields from `sbtest2` 2023-07-11T16:16:27.625027+08:00 2692 Query show fields from `sbtest2` 2023-07-11T16:16:27.625391+08:00 2692 Query SELECT /*!40001 SQL_NO_CACHE */ * FROM `sbtest2` 2023-07-11T16:16:27.636073+08:00 2692 Query SET SESSION character_set_results = 'binary' 2023-07-11T16:16:27.636213+08:00 2692 Query use `testdb_myisam` 2023-07-11T16:16:27.636317+08:00 2692 Query select @@collation_database 2023-07-11T16:16:27.636429+08:00 2692 Query SHOW TRIGGERS LIKE 'sbtest2' 2023-07-11T16:16:27.636923+08:00 2692 Query SET SESSION character_set_results = 'utf8' 2023-07-11T16:16:27.637034+08:00 2692 Query ROLLBACK TO SAVEPOINT sp 2023-07-11T16:16:27.637116+08:00 2692 Query RELEASE SAVEPOINT sp 2023-07-11T16:16:27.637195+08:00 2692 Query show events 2023-07-11T16:16:27.637517+08:00 2692 Query use `testdb_myisam` 2023-07-11T16:16:27.637631+08:00 2692 Query select @@collation_database 2023-07-11T16:16:27.637741+08:00 2692 Query SET SESSION character_set_results = 'binary' 2023-07-11T16:16:27.637839+08:00 2692 Query SHOW FUNCTION STATUS WHERE Db = 'testdb_myisam' 2023-07-11T16:16:27.639206+08:00 2692 Query SHOW PROCEDURE STATUS WHERE Db = 'testdb_myisam' 2023-07-11T16:16:27.640377+08:00 2692 Query SET SESSION character_set_results = 'utf8' 2023-07-11T16:16:27.663274+08:00 2692 Quit 

在从服务器,使用上述 mysqldump 逻辑备份文件执行恢复,搭建从库。

-- 从库查看数据库 mysql> show databases; +--------------------+ | Database | +--------------------+ | information_schema | | mysql | | performance_schema | | sys | +--------------------+ -- 清空从库 binlog 和 gtid 信息 mysql> reset master; -- 查看确认 mysql> show master status\G; *************************** 1. row *************************** File: mysql-bin.000001 Position: 154 Binlog_Do_DB: Binlog_Ignore_DB: Executed_Gtid_Set: 1 row in set (0.00 sec) -- 执行 mysqldump 逻辑备份文件恢复 mysql> source /tmp/dump.sql; -- 建立复制,并启动复制 mysql> change master to MASTER_HOST='10.186.60.187',MASTER_PORT=3307,master_user='repl',master_password='1',MASTER_AUTO_POSITION=1; mysql> start slave; -- 查看复制状态 mysql> show slave status\G; *************************** 1. row *************************** Slave_IO_State: Waiting for master to send event Master_Host: 10.186.60.187 Master_User: repl Master_Port: 3307 Connect_Retry: 60 Master_Log_File: mysql-bin.000015 Read_Master_Log_Pos: 190088135 Relay_Log_File: mysql-relay.000002 Relay_Log_Pos: 414 Relay_Master_Log_File: mysql-bin.000015 Slave_IO_Running: Yes Slave_SQL_Running: No Replicate_Do_DB: Replicate_Ignore_DB: Replicate_Do_Table: Replicate_Ignore_Table: Replicate_Wild_Do_Table: Replicate_Wild_Ignore_Table: Last_Errno: 1062 Last_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction '19112042-1f97-11ee-bf09-02000aba3cbb:3747' at master log mysql-bin.000015, end_log_pos 190087781. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any. Skip_Counter: 0 Exec_Master_Log_Pos: 190087413 Relay_Log_Space: 1339 Until_Condition: None Until_Log_File: Until_Log_Pos: 0 Master_SSL_Allowed: No Master_SSL_CA_File: Master_SSL_CA_Path: Master_SSL_Cert: Master_SSL_Cipher: Master_SSL_Key: Seconds_Behind_Master: NULL Master_SSL_Verify_Server_Cert: No Last_IO_Errno: 0 Last_IO_Error: Last_SQL_Errno: 1062 Last_SQL_Error: Coordinator stopped because there were error(s) in the worker(s). The most recent failure being: Worker 1 failed executing transaction '19112042-1f97-11ee-bf09-02000aba3cbb:3747' at master log mysql-bin.000015, end_log_pos 190087781. See error log and/or performance_schema.replication_applier_status_by_worker table for more details about this failure or others, if any. Replicate_Ignore_Server_Ids: Master_Server_Id: 629181509 Master_UUID: 19112042-1f97-11ee-bf09-02000aba3cbb Master_Info_File: mysql.slave_master_info SQL_Delay: 0 SQL_Remaining_Delay: NULL Slave_SQL_Running_State: Master_Retry_Count: 86400 Master_Bind: Last_IO_Error_Timestamp: Last_SQL_Error_Timestamp: 230711 17:03:01 Master_SSL_Crl: Master_SSL_Crlpath: Retrieved_Gtid_Set: 19112042-1f97-11ee-bf09-02000aba3cbb:3747-3748 Executed_Gtid_Set: 19112042-1f97-11ee-bf09-02000aba3cbb:1-3746 Auto_Position: 1 Replicate_Rewrite_DB: Channel_Name: Master_TLS_Version: 1 row in set (0.00 sec) -- 查看复制具体报错内容 mysql> select * from performance_schema.replication_applier_status_by_worker\G; *************************** 1. row *************************** CHANNEL_NAME: WORKER_ID: 1 THREAD_ID: NULL SERVICE_STATE: OFF LAST_SEEN_TRANSACTION: 19112042-1f97-11ee-bf09-02000aba3cbb:3747 LAST_ERROR_NUMBER: 1062 LAST_ERROR_MESSAGE: Worker 1 failed executing transaction '19112042-1f97-11ee-bf09-02000aba3cbb:3747' at master log mysql-bin.000015, end_log_pos 190087781; Could not execute Write_rows event on table testdb_myisam.sbtest2; Duplicate entry '2' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log FIRST, end_log_pos 190087781 LAST_ERROR_TIMESTAMP: 2023-07-11 17:03:01 

原理分析

  1. 当 mysqldump 开始备份,并获取一致性位点后,UNLOCK TABLES 前,记为 T1 时刻。
  2. 备份 InnoDB 表完成(假设先备份 InnoDB 表),记为 T2 时刻。
  3. 备份 MyISAM 引擎表完成,记为 T3 时刻。
  4. T1T2 之间,如果 MyISAM 引擎表有 INSERT 操作,会有 binlog 产生,mysqldump 也会把 T1T2 之间对 MyISAM 引擎表的 INSERT 数据备份下来。
  5. 这样就产生了,启动复制后,由于 SQL 线程会回放 T1T2 期间的 binlog,而这部分数据已经在备份文件里了,并恢复到从库了,导致 SQL 线程回放报重复键的问题。
  6. 使用该选项时:mysqldump --single-transaction 获取一致性备份只适用于 InnoDB 引擎,对于 InnoDB 引擎表的备份,获取的是 T1 时刻的快照,对于非 InnoDB 引擎表的备份,获取的是当前最新数据。

改进建议

  1. 把业务库的非 InnoDB 引擎表,修改为 InnoDB,重新备份后搭建从库( 修改表的存储引擎开销较大,需要考虑改存储引擎对在线业务的影响,适合表可以改为 InnoDB 引擎的情况)。

  2. 改用 Xtrabackup 备份工具。如果非 InnoDB 的表比较大,备份 MyISAM 引擎期间, 备份线程持有实例的全局读锁(FLUSH TABLES WITH READ LOCK)时间将增加,将影响数据库可用性,选择业务低峰时执行。(适合短时间内无法修改表存储引擎的情况)。

更多技术文章,请访问:https://opensource.actionsky.com/

关于 SQLE

爱可生开源社区的 SQLE 是一款面向数据库使用者和管理者,支持多场景审核,支持标准化上线流程,原生支持 MySQL 审核且数据库类型可扩展的 SQL 审核工具。

SQLE 获取

类型 地址
版本库 https://github.com/actiontech/sqle
文档 https://actiontech.github.io/sqle-docs/
发布信息 https://github.com/actiontech/sqle/releases
数据审核插件开发文档 https://actiontech.github.io/sqle-docs/docs/dev-manual/plugins/howtouse
原文链接:https://my.oschina.net/actiontechoss/blog/10090762
关注公众号

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。

持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。

转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。

文章评论

共有0条评论来说两句吧...

文章二维码

扫描即可查看该文章

点击排行

推荐阅读

最新文章