跳过复制错误——slave_skip_errorsslave_exec_mode

Posted 醒嘞

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跳过复制错误——slave_skip_errorsslave_exec_mode相关的知识,希望对你有一定的参考价值。

这一篇写写复制错误处理相关的另两个参数slave_skip_errors、slave_exec_mode,基本环境参考《复制错误处理——sql_slave_skip_counter

一、slave_skip_errors

1.1、slave_skip_errors官方解释

https://dev.mysql.com/doc/refman/5.7/en/replication-options-slave.html
--slave-skip-errors=[err_code1,err_code2,...|all|ddl_exist_errors]
Normally, replication stops when an error occurs on the slave, which gives you the opportunity to resolve the inconsistency in the data manually. This option causes the slave SQL thread to continue replication when a statement returns any of the errors listed in the option value.
Do not use this option unless you fully understand why you are getting errors. If there are no bugs in your replication setup and client programs, and no bugs in mysql itself, an error that stops replication should never occur. Indiscriminate use of this option results in slaves becoming hopelessly out of synchrony with the master, with you having no idea why this has occurred.

1.2、测试数据

slave_skip_errors是一个非Dynamic变量,在配置文件中添加

[mysqld]
slave_skip_errors=1032,1062
View Code

主库创建一个事务表和一个非事务表,然后从库往各表写入id=1的记录

# 主库创建测试表
mydba@192.168.85.132,3306 [replcrash]> create table repl_innodb(id int primary key,name1 char(10),name2 char(10)) engine=innodb;
mydba@192.168.85.132,3306 [replcrash]> create table repl_myisam(id int primary key,name1 char(10),name2 char(10)) engine=myisam;

# 从库往测试表中添加数据,不记入binlog
mydba@192.168.85.133,3306 [replcrash]> set sql_log_bin=0;
mydba@192.168.85.133,3306 [replcrash]> insert into repl_innodb(id,name1,name2) values(1,\'s1062-1\',\'s1062-1\');
mydba@192.168.85.133,3306 [replcrash]> insert into repl_myisam(id,name1,name2) values(1,\'s1062-1\',\'s1062-1\');
mydba@192.168.85.133,3306 [replcrash]> set sql_log_bin=1;
View Code

1.3、一个事务中包含事务表和非事务表操作

这里不再单独对事务表和非事务表进行测试

# 主库往事务表、非事务表中添加数据
mydba@192.168.85.132,3306 [replcrash]> begin;
mydba@192.168.85.132,3306 [replcrash]> insert into repl_innodb(id,name1,name2) values(1,\'m1062-1\',\'m1062-1\');
mydba@192.168.85.132,3306 [replcrash]> insert into repl_innodb(id,name1,name2) values(2,\'m1062-2\',\'m1062-2\');
mydba@192.168.85.132,3306 [replcrash]> insert into repl_myisam(id,name1,name2) values(1,\'m1062-1\',\'m1062-1\');
mydba@192.168.85.132,3306 [replcrash]> insert into repl_myisam(id,name1,name2) values(2,\'m1062-2\',\'m1062-2\');
mydba@192.168.85.132,3306 [replcrash]> commit;

# 主库数据
mydba@192.168.85.132,3306 [replcrash]> select * from repl_innodb;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  1 | m1062-1 | m1062-1 |
|  2 | m1062-2 | m1062-2 |
+----+---------+---------+
mydba@192.168.85.132,3306 [replcrash]> select * from repl_myisam;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  1 | m1062-1 | m1062-1 |
|  2 | m1062-2 | m1062-2 |
+----+---------+---------+

# 从库数据
mydba@192.168.85.133,3306 [replcrash]> select * from repl_innodb;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  1 | s1062-1 | s1062-1 |
|  2 | m1062-2 | m1062-2 |
+----+---------+---------+
mydba@192.168.85.133,3306 [replcrash]> select * from repl_myisam;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  1 | s1062-1 | s1062-1 |
|  2 | m1062-2 | m1062-2 |
+----+---------+---------+
View Code

复制正常,从库repl_myisam表跳过id=1的记录,复制了id=2的记录;从库repl_innodb表跳过id=1的记录,复制了id=2的记录
语句操作过程:开启显式事务1,往repl_innodb表写入id=1、2两条记录-->开启事务2,往repl_myisam表写入id=1记录,提交事务2-->开启事务3,往repl_myisam表写入id=2记录,提交事务3-->提交显式事务1
当事务2提交后,从库上repl_myisam.id=1的Duplicate entry被skip;当事务3提交后,从库写入repl_myisam.id=2的记录;当事务1提交后,从库上repl_innodb.id=1的Duplicate entry被skip,从库写入repl_innodb.id=2的记录~
也就是说配置文件中的slave_skip_errors=1032,1062 它仅跳过出错的行,并不是跳过整个事务(sql_slave_skip_counter会跳过整个事务)
试想,如果主库上的显式事务中有update操作,然后在从库找不到对应行,它仅跳过出错的行,主从不一致的情况将继续,并且不会触发错误

[root@ZST1 logs]# mysqlbinlog -v --base64-output=decode-rows mysql-bin.000008 --start-position=1333
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 1333
#171201 21:08:18 server id 1323306  end_log_pos 1398 CRC32 0xd792f990   Anonymous_GTID  last_committed=5        sequence_number=6       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= \'ANONYMOUS\'/*!*/;
# at 1398
#171201 21:08:18 server id 1323306  end_log_pos 1475 CRC32 0x1869ed89   Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1512133698/*!*/;
SET @@session.pseudo_thread_id=3/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
SET @@session.auto_increment_increment=1, @@session.auto_increment_offset=1/*!*/;
/*!\\C utf8 *//*!*/;
SET @@session.character_set_client=33,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
SET @@session.lc_time_names=0/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
==================== repl_myisam表写入id=1的记录Start ====================
BEGIN
/*!*/;
# at 1475
#171201 21:08:18 server id 1323306  end_log_pos 1540 CRC32 0x7f6a1e44   Table_map: `replcrash`.`repl_myisam` mapped to number 307
# at 1540
#171201 21:08:18 server id 1323306  end_log_pos 1596 CRC32 0xb6784f59   Write_rows: table id 307 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
###   @1=1
###   @2=\'m1062-1\'
###   @3=\'m1062-1\'
# at 1596
#171201 21:08:18 server id 1323306  end_log_pos 1674 CRC32 0xdebe509f   Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1512133698/*!*/;
COMMIT
/*!*/;
# at 1674
==================== repl_myisam表写入id=1的记录End ====================
#171201 21:08:40 server id 1323306  end_log_pos 1739 CRC32 0x09f01ffa   Anonymous_GTID  last_committed=6        sequence_number=7       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= \'ANONYMOUS\'/*!*/;
# at 1739
#171201 21:08:40 server id 1323306  end_log_pos 1816 CRC32 0x9b1cba09   Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1512133720/*!*/;
BEGIN
/*!*/;
# at 1816
#171201 21:08:40 server id 1323306  end_log_pos 1881 CRC32 0xf8e7ddd7   Table_map: `replcrash`.`repl_myisam` mapped to number 307
# at 1881
#171201 21:08:40 server id 1323306  end_log_pos 1937 CRC32 0xa2150d71   Write_rows: table id 307 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
###   @1=2
###   @2=\'m1062-2\'
###   @3=\'m1062-2\'
# at 1937
#171201 21:08:40 server id 1323306  end_log_pos 2015 CRC32 0xb007bae6   Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1512133720/*!*/;
COMMIT
/*!*/;
# at 2015
==================== repl_myisam表写入id=2的记录End ====================
#171201 21:08:56 server id 1323306  end_log_pos 2080 CRC32 0x39e67db5   Anonymous_GTID  last_committed=7        sequence_number=8       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= \'ANONYMOUS\'/*!*/;
# at 2080
#171201 21:07:59 server id 1323306  end_log_pos 2157 CRC32 0xb1ae59f2   Query   thread_id=3     exec_time=0     error_code=0
SET TIMESTAMP=1512133679/*!*/;
==================== repl_innodb表写入id=1、2的记录,在一个事务中Start ====================
BEGIN
/*!*/;
# at 2157
#171201 21:07:59 server id 1323306  end_log_pos 2222 CRC32 0x09d40a4f   Table_map: `replcrash`.`repl_innodb` mapped to number 306
# at 2222
#171201 21:07:59 server id 1323306  end_log_pos 2278 CRC32 0x834f2f78   Write_rows: table id 306 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
###   @1=1
###   @2=\'m1062-1\'
###   @3=\'m1062-1\'
# at 2278
#171201 21:08:07 server id 1323306  end_log_pos 2343 CRC32 0x5b7e244b   Table_map: `replcrash`.`repl_innodb` mapped to number 306
# at 2343
#171201 21:08:07 server id 1323306  end_log_pos 2399 CRC32 0x965812b9   Write_rows: table id 306 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
###   @1=2
###   @2=\'m1062-2\'
###   @3=\'m1062-2\'
# at 2399
#171201 21:08:56 server id 1323306  end_log_pos 2430 CRC32 0xbddc1af8   Xid = 1076
COMMIT/*!*/;
==================== repl_innodb表写入id=1、2的记录,在一个事务中End ====================
SET @@SESSION.GTID_NEXT= \'AUTOMATIC\' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;
[root@ZST1 logs]# 
View Binlog

注意:如果主库使用insert into repl_innodb(id,name1,name2) values(1,\'m1062-1\',\'m1062-1\'),(2,\'m1062-2\',\'m1062-2\');
复制正常,从库直接跳过整个事务,主上id=1、2记录不会插入到从库,这种写法id=1和id=2之间是没有position分隔(解析binlog可以看出)

二、slave_exec_mode

2.1、slave_exec_mode官方解释

https://dev.mysql.com/doc/refman/5.7/en/replication-options-slave.html
SET GLOBAL slave_exec_mode = [\'IDEMPOTENT\'|\'STRICT\']
Controls how a slave thread resolves conflicts and errors during replication. IDEMPOTENT mode causes suppression of duplicate-key and no-key-found errors; STRICT means no such suppression takes place.
IDEMPOTENT mode is intended for use in multi-master replication, circular replication, and some other special replication scenarios for NDB Cluster Replication.
For storage engines other than NDB, IDEMPOTENT mode should be used only when you are absolutely sure that duplicate-key errors and key-not-found errors can safely be ignored. It is meant to be used in fail-over scenarios for NDB Cluster where multi-master replication or circular replication is employed, and is not recommended for use in other cases.

2.2、初始数据

注释配置文件中的slave_skip_errors,然后初始数据

# 主库数据
mydba@192.168.85.132,3306 [replcrash]> select * from repl_innodb;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  2 | m1032-2 | m1032-2 |
|  3 | m1032-3 | m1032-3 |
+----+---------+---------+
mydba@192.168.85.132,3306 [replcrash]> select * from repl_myisam;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  2 | m1032-2 | m1032-2 |
|  3 | m1032-3 | m1032-3 |
+----+---------+---------+

# 从库数据
mydba@192.168.85.133,3306 [replcrash]> select * from repl_innodb;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  1 | s1062-1 | s1062-1 |
+----+---------+---------+
mydba@192.168.85.133,3306 [replcrash]> select * from repl_myisam;
+----+---------+---------+
| id | name1   | name2   |
+----+---------+---------+
|  1 | s1062-1 | s1062-1 |
+----+---------+---------+
View Code

这里只是为了模拟1062(insert遇到duplicate-key)、1032(delete/update遇到no-key-found)错误

2.3、一个事务中包含事务表和非事务表操作

这里不再单独对事务表和非事务表进行测试

# 主库开启事务,insertupdatedelete
mydba@192.168.85.132,3306 [replcrash]> begin;
mydba@192.168.85.132,3306 [replcrash]> insert into repl_innodb(id,name1,name2) values(1,\'m1062-1\',\'m1062-1\');
mydba@192.168.85.132,3306 [replcrash]> update repl_innodb set name1=\'m1032-2upd\' where id = 2;
mydba@192.168.85.132,3306 [replcrash]> delete from repl_innodb where id=3;
mydba@192.168.85.132,3306 [replcrash]> insert into repl_innodb(id,name1,name2) values(4,\'m1062-4\',\'m1062-4\');
mydba@192.168.85.132,3306 [replcrash]> insert into repl_myisam(id,name1,name2) values(1,\'m1062-1\',\'m1062-1\');
mydba@192.168.85.132,3306 [replcrash主从复制中从库Last_SQL_Errno: 1062  错误

复制错误跳过

MySQL跳过复制错误

Amazon RDS 只读副本——跳过复制错误

mariadb多源主从复制错误跳过.md

如何忽略错误但不跳过 redshift 复制命令中的行