这一篇写写复制错误处理相关的另两个参数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=,

主库创建一个事务表和一个非事务表,然后从库往各表写入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;

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 |
+----+---------+---------+

复制正常,从库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. --start-position=
/*! SET @@SESSION.PSEUDO_SLAVE_MODE=*/;
/*! SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=*/;
DELIMITER /*!*/;
# at
# :: server id end_log_pos CRC32 0xd792f990 Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*! SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0x1869ed89 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.pseudo_thread_id=/*!*/;
SET @@session.foreign_key_checks=, @@session.sql_auto_is_null=, @@session.unique_checks=, @@session.autocommit=/*!*/;
SET @@session.sql_mode=/*!*/;
SET @@session.auto_increment_increment=, @@session.auto_increment_offset=/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=,@@session.collation_connection=,@@session.collation_server=/*!*/;
SET @@session.lc_time_names=/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
==================== repl_myisam表写入id=1的记录Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x7f6a1e44 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0xb6784f59 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
### @1=
### @2='m1062-1'
### @3='m1062-1'
# at
# :: server id end_log_pos CRC32 0xdebe509f Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表写入id=1的记录End ====================
# :: server id end_log_pos CRC32 0x09f01ffa Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*! SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0x9b1cba09 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0xf8e7ddd7 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0xa2150d71 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
### @1=
### @2='m1062-2'
### @3='m1062-2'
# at
# :: server id end_log_pos CRC32 0xb007bae6 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表写入id=2的记录End ====================
# :: server id end_log_pos CRC32 0x39e67db5 Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*! SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0xb1ae59f2 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
==================== repl_innodb表写入id=、2的记录,在一个事务中Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x09d40a4f Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0x834f2f78 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
### @1=
### @2='m1062-1'
### @3='m1062-1'
# at
# :: server id end_log_pos CRC32 0x5b7e244b Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0x965812b9 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
### @1=
### @2='m1062-2'
### @3='m1062-2'
# at
# :: server id end_log_pos CRC32 0xbddc1af8 Xid =
COMMIT/*!*/;
==================== repl_innodb表写入id=、2的记录,在一个事务中End ====================
SET @@SESSION.GTID_NEXT= 'AUTOMATIC' /* added by mysqlbinlog */ /*!*/;
DELIMITER ;
# End of log file
/*! SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*! SET @@SESSION.PSEUDO_SLAVE_MODE=*/;
[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 |
+----+---------+---------+

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

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

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

# 主库开启事务,insert、update、delete
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]> update repl_myisam set name1='m1032-2upd' where id = 2;
mydba@192.168.85.132,3306 [replcrash]> delete from repl_myisam where id=3;
mydba@192.168.85.132,3306 [replcrash]> insert into repl_myisam(id,name1,name2) values(4,'m1062-4','m1062-4');
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 | m1032-2upd | m1032-2 |
| 4 | m1062-4 | m1062-4 |
+----+------------+---------+
mydba@192.168.85.132,3306 [replcrash]> select * from repl_myisam;
+----+------------+---------+
| id | name1 | name2 |
+----+------------+---------+
| 1 | m1062-1 | m1062-1 |
| 2 | m1032-2upd | m1032-2 |
| 4 | m1062-4 | m1062-4 |
+----+------------+---------+

从库在应用insert into repl_myisam(id,name1,name2) values(1,'m1062-1','m1062-1')时,从库报错replcrash.repl_myisam; Duplicate entry '1',SQL thread停止。前面对repl_innodb的操作还没有commit,所以从库此时数据没有任何变化。尝试设置从库设置slave_exec_mode参数

# 从库设置slave_exec_mode='IDEMPOTENT'
mydba@192.168.85.133,3306 [(none)]> set global slave_exec_mode='IDEMPOTENT';
mydba@192.168.85.133,3306 [(none)]> start slave sql_thread; # 从库数据
mydba@192.168.85.133,3306 [replcrash]> select * from repl_innodb;
+----+---------+---------+
| id | name1 | name2 |
+----+---------+---------+
| 1 | m1062-1 | m1062-1 |
| 4 | m1062-4 | m1062-4 |
+----+---------+---------+
mydba@192.168.85.133,3306 [replcrash]> select * from repl_myisam;
+----+---------+---------+
| id | name1 | name2 |
+----+---------+---------+
| 1 | m1062-1 | m1062-1 |
| 4 | m1062-4 | m1062-4 |
+----+---------+---------+

从库更新了id=1的记录,写入了id=4的记录,它是以什么顺序来执行的呢?我们先来查看主库上的binlog

[root@ZST1 logs]# mysqlbinlog -v --base64-output=decode-rows mysql-bin. --start-position=
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at
# :: server id end_log_pos CRC32 0x99557a42 Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0xdcd2d27f Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.pseudo_thread_id=/*!*/;
SET @@session.foreign_key_checks=, @@session.sql_auto_is_null=, @@session.unique_checks=, @@session.autocommit=/*!*/;
SET @@session.sql_mode=/*!*/;
SET @@session.auto_increment_increment=, @@session.auto_increment_offset=/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=,@@session.collation_connection=,@@session.collation_server=/*!*/;
SET @@session.lc_time_names=/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
==================== repl_myisam表写入id=1的记录Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x48b4dd17 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0x8d519b60 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
### @=
### @='m1062-1'
### @='m1062-1'
# at
# :: server id end_log_pos CRC32 0xe0be0f09 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表写入id=1的记录End ====================
# :: server id end_log_pos CRC32 0xfb8a1915 Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0xf2abbe32 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
==================== repl_myisam表更新id=2的记录Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x2b4285a4 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0x6f94f7cb Update_rows: table id flags: STMT_END_F
### UPDATE `replcrash`.`repl_myisam`
### WHERE
### @=
### @='m1032-2'
### @='m1032-2'
### SET
### @=
### @='m1032-2upd'
### @='m1032-2'
# at
# :: server id end_log_pos CRC32 0x2a8e5489 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表更新id=2的记录End ====================
# :: server id end_log_pos CRC32 0xc7ef1e5e Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0xcf5e63ac Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
==================== repl_myisam表删除id=3的记录Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0xb6020c12 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0x5fc1ee98 Delete_rows: table id flags: STMT_END_F
### DELETE FROM `replcrash`.`repl_myisam`
### WHERE
### @=
### @='m1032-3'
### @='m1032-3'
# at
# :: server id end_log_pos CRC32 0x6aab62fd Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表删除id=3的记录End ====================
# :: server id end_log_pos CRC32 0xed36610c Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0x5a134f60 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
==================== repl_myisam表写入id=4的记录Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x317d7f86 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0x50f84020 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
### @=
### @='m1062-4'
### @='m1062-4'
# at
# :: server id end_log_pos CRC32 0xdc200995 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表写入id=4的记录End ====================
# :: server id end_log_pos CRC32 0xaae63436 Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0xb14f2893 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
==================== repl_innodb表操作id=、、、4的记录,在一个事务中Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x62020112 Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0xa6c81e06 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
### @=
### @='m1062-1'
### @='m1062-1'
# at
# :: server id end_log_pos CRC32 0x0a4abc3c Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0xdcd94aa2 Update_rows: table id flags: STMT_END_F
### UPDATE `replcrash`.`repl_innodb`
### WHERE
### @=
### @='m1032-2'
### @='m1032-2'
### SET
### @=
### @='m1032-2upd'
### @='m1032-2'
# at
# :: server id end_log_pos CRC32 0xf5a4c9ba Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0xbd1864f7 Delete_rows: table id flags: STMT_END_F
### DELETE FROM `replcrash`.`repl_innodb`
### WHERE
### @=
### @='m1032-3'
### @='m1032-3'
# at
# :: server id end_log_pos CRC32 0x89bcb330 Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0x80d6ed1a Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
### @=
### @='m1062-4'
### @='m1062-4'
# at
# :: server id end_log_pos CRC32 0xdc2e8ab8 Xid =
COMMIT/*!*/;
==================== repl_innodb表操作id=、、、4的记录,在一个事务中Start ====================
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]#

Master Binlog

语句操作过程:开启显式事务1,往repl_innodb表操作id=1(ins)、2(upd)、3(del)、4(ins)的记录-->开启事务2,往repl_myisam表写入id=1的记录,提交事务2-->开启事务3,更新repl_myisam表id=2的记录,提交事务3-->开启事务4,删除repl_myisam表id=3的记录,提交事务4-->开启事务5,往repl_myisam表写入id=4的记录,提交事务5-->提交显式事务1
binlog中我们可以看出,是按commit顺序,先记录repl_myisam的操作,然后记录repl_innodb的操作^_-
我们再来查看从库上的binlog

[root@ZST2 logs]# mysqlbinlog -v --base64-output=decode-rows mysql-bin.
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at
# :: server id end_log_pos CRC32 0xb5872a85 Start: binlog v , server v 5.7.-log created :: at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
# at
# :: server id end_log_pos CRC32 0x2f0d74be Previous-GTIDs
# [empty]
# at
# :: server id end_log_pos CRC32 0x227de897 Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0x9bd4c099 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.pseudo_thread_id=/*!*/;
SET @@session.foreign_key_checks=, @@session.sql_auto_is_null=, @@session.unique_checks=, @@session.autocommit=/*!*/;
SET @@session.sql_mode=/*!*/;
SET @@session.auto_increment_increment=, @@session.auto_increment_offset=/*!*/;
/*!\C utf8 *//*!*/;
SET @@session.character_set_client=,@@session.collation_connection=,@@session.collation_server=/*!*/;
SET @@session.lc_time_names=/*!*/;
SET @@session.collation_database=DEFAULT/*!*/;
==================== repl_myisam表写入id=1的记录,重复key进行update操作,Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0xe221b9d8 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0x32dc6ddc Update_rows: table id flags: STMT_END_F
### UPDATE `replcrash`.`repl_myisam`
### WHERE
### @=
### @='s1062-1'
### @='s1062-1'
### SET
### @=
### @='m1062-1'
### @='m1062-1'
# at
# :: server id end_log_pos CRC32 0x8e56c4de Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.sql_mode=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表写入id=1的记录,重复key进行update操作,End ==================== ==================== repl_myisam表更新id=、删除id=3的记录Start ====================
update/delete 在从库没找到记录,没有做任何处理,相当于skip
==================== repl_myisam表更新id=、删除id=3的记录End ==================== # :: server id end_log_pos CRC32 0x0401a98f Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0xb8743fdf Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.sql_mode=/*!*/;
==================== repl_myisam表写入id=4的记录Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x8dc365d7 Table_map: `replcrash`.`repl_myisam` mapped to number
# at
# :: server id end_log_pos CRC32 0x773e7fc0 Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
### @=
### @='m1062-4'
### @='m1062-4'
# at
# :: server id end_log_pos CRC32 0x221bf96b Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.sql_mode=/*!*/;
COMMIT
/*!*/;
# at
==================== repl_myisam表写入id=4的记录End ====================
# :: server id end_log_pos CRC32 0x4e47e1fc Anonymous_GTID last_committed= sequence_number= rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at
# :: server id end_log_pos CRC32 0x081b8094 Query thread_id= exec_time= error_code=
SET TIMESTAMP=/*!*/;
SET @@session.sql_mode=/*!*/;
==================== repl_innodb表操作id=、4的记录(、3被skip),在一个事务中Start ====================
BEGIN
/*!*/;
# at
# :: server id end_log_pos CRC32 0x9797a0bd Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0xe457ab20 Update_rows: table id flags: STMT_END_F
### UPDATE `replcrash`.`repl_innodb`
### WHERE
### @=
### @='s1062-1'
### @='s1062-1'
### SET
### @=
### @='m1062-1'
### @='m1062-1'
# at
# :: server id end_log_pos CRC32 0x6fd579ab Table_map: `replcrash`.`repl_innodb` mapped to number
# at
# :: server id end_log_pos CRC32 0x6c5678ef Write_rows: table id flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
### @=
### @='m1062-4'
### @='m1062-4'
# at
# :: server id end_log_pos CRC32 0x594d2812 Xid =
COMMIT/*!*/;
==================== repl_innodb表操作id=、4的记录(、3被skip),在一个事务中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@ZST2 logs]#

Slave Binlog

它也是按照主库的binlog的顺序,先提交repl_myisam操作,再提交repl_innodb操作。对于insert在从库有重复记录的,从库update为主库的值;对于update/delete在从库没找到记录的,不做任何处理,相当于skip~
When slave_exec_mode is IDEMPOTENT, a failure to apply changes from RBL(Row-Based Logging) because the original row cannot be found does not trigger an error or cause replication to fail. This means that it is possible that updates are not applied on the slave, so that the master and slave are no longer synchronized. Latency issues and use of nontransactional tables with RBR(Statement-Based Logging) when slave_exec_mode is IDEMPOTENT can cause the master and slave to diverge even further.

三、总结

正常情况下,应该是从库遇到错误就停止复制,然后人工去处理数据一致性问题。slave-skip-errors选项会导致SQL thread遇到配置中的错误后继续复制。滥用slave-skip-errors会在你全然不知的情况下导致主从数据不一致。
slave_exec_mode='IDEMPOTENT',适合多主、循环、以及其他特殊复制场景。RBL(Row-Based Logging)环境下也会出现SBL(Statement-Based Logging)场景中主从数据不一致,复制状态正常
遇到复制中断第一时间要想怎么满足这个复制,而不是去跳过这个事务(・ω・)

跳过复制错误——slave_skip_errors、slave_exec_mode的更多相关文章

  1. 跳过复制错误——sql_slave_skip_counter

    昨天不少同学讨论<小心,前方有雷 —— sql_slave_skip_counter>,有说作者在玩文字游戏,扯了那么多sql_slave_skip_counter=1不还是跳过一个事务嘛 ...

  2. mysql主从复制跳过复制错误【转】

    跳过复制错误 mysql因为binlog机制问题,有些时候会出现从库重放sql执行失败的情况,特别是旧的STATEMENT模式最容易出现这种情况(因为函数和存储过程等原因),这也是为什么强调使用mix ...

  3. MySQL-Utilities:mysqldbcompare及跳过复制错误

    mysqldbcompare也是MySQL-Utilities工具集的一个脚本.mysqldbcompare从两个数据库比较对象和数据的不同.数据库中的对象包括:表.视图.触发器.存储过程.函数和事件 ...

  4. MySQL Replication--跳过复制错误

    在MySQL中,有两种跳过复制错误的方法:1.对于未使用GTID的复制,可以使用sql_slave_skip_counter来跳过错误2.对于使用GTID的复制,可以使用GTID_NEXT模拟空事务来 ...

  5. mysql 5.6在gtid复制模式下复制错误,如何跳过??

    mysql 5.6在gtid复制模式下复制错误,如何跳过?? http://www.xuchanggang.cn/archives/918.html

  6. replicate-do-db参数引起的MySQL复制错误及处理办法

    replicate-do-db配置在MySQL从库的my.cnf文件中,可以指定只复制哪个库的数据.但是这个参数有个问题就是主库如果在其他的schema环境下操作,其binlog不会被从库应用,从而出 ...

  7. JSP中,当页面为404或者500时。设置跳转到错误提示页面

    最好的就是在WEB.XML文件中配置错误代码的跳转页面,首先建立个 出现500错误的页面,提示出错了,然后再WEB.XML文件中配置,配置如下 一. 通过错误码来配置error-page <er ...

  8. MySQL复制错误1837的相关缺陷一例

    故障现象 主从gtid报错,复制错误1837,这个复制故障可以说是第一次遇到. Last_Errno: 1837 Last_Error: Error 'When @@SESSION.GTID_NEXT ...

  9. SpringBoot图文教程15—项目异常怎么办?「跳转404错误页面」「全局异常捕获」

    有天上飞的概念,就要有落地的实现 概念十遍不如代码一遍,朋友,希望你把文中所有的代码案例都敲一遍 先赞后看,养成习惯 SpringBoot 图文教程系列文章目录 SpringBoot图文教程1-Spr ...

随机推荐

  1. Invalid AABB inAABB UnityEngine.Canvas:SendWillRenderCanvases()的解决办法

    我遇到这个问题的情况是, 在Start()中直接使用WWW价值本地图片,可能是加载图片相对比较耗时,就出现了这个错误. 解决的办法是使用协程: // Use this for initializati ...

  2. PAT甲题题解-1014. Waiting in Line (30)-模拟,优先级队列

    题意:n个窗口,每个窗口可以排m人.有k为顾客需要办理业务,给出了每个客户的办理业务时间.银行在8点开始服务,如果窗口都排满了,客户就得在黄线外等候.如果有一个窗口用户服务结束,黄线外的客户就进来一个 ...

  3. 【MOOC EXP】Linux内核分析实验二报告

    程涵  原创博客 <Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000  [操作系统是如何工作的]   教学内 ...

  4. time since epoch

    C++11 提供了新的获取系统时间的库函数,在获取时间的时候一般常用的是获取time since epoch,下面来看一下如何获取这个时间. #include <iostream> #in ...

  5. final发布简评

    1.nice!——约跑app:本次发布使用摄像头展示,比之前清晰的多,展示效果很好,值得学习!功能都已实现,已经可以使用,好评. 2.飞天小女警——礼物挑选:本次发布风格与上次不同,除此之外添加了猜你 ...

  6. mysql 存储过程中结尾分割符修改

    mysql中修改命令结束符delimiter的用法:mysql中的delimiter会告诉MySQL解释器,命令的结束符是什么,默认情况下MySQL的命令是以分号(;)结束的.在遇到(;)时,MySQ ...

  7. Windows 下面简单的同步文件夹工具

    1. 微软自己的工具 下载地址 https://www.microsoft.com/en-us/download/confirmation.aspx?id=15155 2. 安装过程忽略 3. 配置与 ...

  8. CentOS下部署Jupyter

    目录 安装 配置 准备密码密文 生成配置文件 修改配置 启动 参考:在服务器搭建Jupyter notebook 安装 为了环境比较轻,使用pip安装,非Anaconda: # 创建Python虚拟环 ...

  9. 跨语言通信方案的比较—Thrift、Protobuf和Avro

    Thrift由Facebook开源的一个RPC框架,用来进行可扩展且跨语言的服务的开发,使得各种编程语言间无缝结合的.高效的服务.我们依据Thrift的规范 简单定义访问接口,通过Thrift编译器编 ...

  10. 【大数据】SparkStreaming学习笔记

    第1章 Spark Streaming概述 1.1 Spark Streaming是什么 Spark Streaming用于流式数据的处理.Spark Streaming支持的数据输入源很多,例如:K ...