跳過復制錯誤——slave_skip_errors、slave_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]> 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 |
+----+------------+---------+
View Code

從庫在應用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 |
+----+---------+---------+
View Code

從庫更新了id=1的記錄,寫入了id=4的記錄,它是以什么順序來執行的呢?我們先來查看主庫上的binlog

[root@ZST1 logs]# mysqlbinlog -v --base64-output=decode-rows mysql-bin.000008 --start-position=2430
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 2430
#171201 23:01:19 server id 1323306  end_log_pos 2495 CRC32 0x99557a42   Anonymous_GTID  last_committed=8        sequence_number=9       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 2495
#171201 23:01:19 server id 1323306  end_log_pos 2572 CRC32 0xdcd2d27f   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140479/*!*/;
SET @@session.pseudo_thread_id=13/*!*/;
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 2572
#171201 23:01:19 server id 1323306  end_log_pos 2637 CRC32 0x48b4dd17   Table_map: `replcrash`.`repl_myisam` mapped to number 309
# at 2637
#171201 23:01:19 server id 1323306  end_log_pos 2693 CRC32 0x8d519b60   Write_rows: table id 309 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
###   @1=1
###   @2='m1062-1'
###   @3='m1062-1'
# at 2693
#171201 23:01:19 server id 1323306  end_log_pos 2771 CRC32 0xe0be0f09   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140479/*!*/;
COMMIT
/*!*/;
# at 2771
==================== repl_myisam表寫入id=1的記錄End ====================
#171201 23:01:36 server id 1323306  end_log_pos 2836 CRC32 0xfb8a1915   Anonymous_GTID  last_committed=9        sequence_number=10      rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 2836
#171201 23:01:36 server id 1323306  end_log_pos 2913 CRC32 0xf2abbe32   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140496/*!*/;
==================== repl_myisam表更新id=2的記錄Start ====================
BEGIN
/*!*/;
# at 2913
#171201 23:01:36 server id 1323306  end_log_pos 2978 CRC32 0x2b4285a4   Table_map: `replcrash`.`repl_myisam` mapped to number 309
# at 2978
#171201 23:01:36 server id 1323306  end_log_pos 3059 CRC32 0x6f94f7cb   Update_rows: table id 309 flags: STMT_END_F
### UPDATE `replcrash`.`repl_myisam`
### WHERE
###   @1=2
###   @2='m1032-2'
###   @3='m1032-2'
### SET
###   @1=2
###   @2='m1032-2upd'
###   @3='m1032-2'
# at 3059
#171201 23:01:36 server id 1323306  end_log_pos 3137 CRC32 0x2a8e5489   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140496/*!*/;
COMMIT
/*!*/;
# at 3137
==================== repl_myisam表更新id=2的記錄End ====================
#171201 23:01:45 server id 1323306  end_log_pos 3202 CRC32 0xc7ef1e5e   Anonymous_GTID  last_committed=10       sequence_number=11      rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 3202
#171201 23:01:45 server id 1323306  end_log_pos 3279 CRC32 0xcf5e63ac   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140505/*!*/;
==================== repl_myisam表刪除id=3的記錄Start ====================
BEGIN
/*!*/;
# at 3279
#171201 23:01:45 server id 1323306  end_log_pos 3344 CRC32 0xb6020c12   Table_map: `replcrash`.`repl_myisam` mapped to number 309
# at 3344
#171201 23:01:45 server id 1323306  end_log_pos 3400 CRC32 0x5fc1ee98   Delete_rows: table id 309 flags: STMT_END_F
### DELETE FROM `replcrash`.`repl_myisam`
### WHERE
###   @1=3
###   @2='m1032-3'
###   @3='m1032-3'
# at 3400
#171201 23:01:45 server id 1323306  end_log_pos 3478 CRC32 0x6aab62fd   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140505/*!*/;
COMMIT
/*!*/;
# at 3478
==================== repl_myisam表刪除id=3的記錄End ====================
#171201 23:01:52 server id 1323306  end_log_pos 3543 CRC32 0xed36610c   Anonymous_GTID  last_committed=11       sequence_number=12      rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 3543
#171201 23:01:52 server id 1323306  end_log_pos 3620 CRC32 0x5a134f60   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140512/*!*/;
==================== repl_myisam表寫入id=4的記錄Start ====================
BEGIN
/*!*/;
# at 3620
#171201 23:01:52 server id 1323306  end_log_pos 3685 CRC32 0x317d7f86   Table_map: `replcrash`.`repl_myisam` mapped to number 309
# at 3685
#171201 23:01:52 server id 1323306  end_log_pos 3741 CRC32 0x50f84020   Write_rows: table id 309 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
###   @1=4
###   @2='m1062-4'
###   @3='m1062-4'
# at 3741
#171201 23:01:52 server id 1323306  end_log_pos 3819 CRC32 0xdc200995   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140512/*!*/;
COMMIT
/*!*/;
# at 3819
==================== repl_myisam表寫入id=4的記錄End ====================
#171201 23:01:58 server id 1323306  end_log_pos 3884 CRC32 0xaae63436   Anonymous_GTID  last_committed=12       sequence_number=13      rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 3884
#171201 23:00:04 server id 1323306  end_log_pos 3961 CRC32 0xb14f2893   Query   thread_id=13    exec_time=0     error_code=0
SET TIMESTAMP=1512140404/*!*/;
==================== repl_innodb表操作id=123、4的記錄,在一個事務中Start ====================
BEGIN
/*!*/;
# at 3961
#171201 23:00:04 server id 1323306  end_log_pos 4026 CRC32 0x62020112   Table_map: `replcrash`.`repl_innodb` mapped to number 308
# at 4026
#171201 23:00:04 server id 1323306  end_log_pos 4082 CRC32 0xa6c81e06   Write_rows: table id 308 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
###   @1=1
###   @2='m1062-1'
###   @3='m1062-1'
# at 4082
#171201 23:00:14 server id 1323306  end_log_pos 4147 CRC32 0x0a4abc3c   Table_map: `replcrash`.`repl_innodb` mapped to number 308
# at 4147
#171201 23:00:14 server id 1323306  end_log_pos 4228 CRC32 0xdcd94aa2   Update_rows: table id 308 flags: STMT_END_F
### UPDATE `replcrash`.`repl_innodb`
### WHERE
###   @1=2
###   @2='m1032-2'
###   @3='m1032-2'
### SET
###   @1=2
###   @2='m1032-2upd'
###   @3='m1032-2'
# at 4228
#171201 23:00:22 server id 1323306  end_log_pos 4293 CRC32 0xf5a4c9ba   Table_map: `replcrash`.`repl_innodb` mapped to number 308
# at 4293
#171201 23:00:22 server id 1323306  end_log_pos 4349 CRC32 0xbd1864f7   Delete_rows: table id 308 flags: STMT_END_F
### DELETE FROM `replcrash`.`repl_innodb`
### WHERE
###   @1=3
###   @2='m1032-3'
###   @3='m1032-3'
# at 4349
#171201 23:00:32 server id 1323306  end_log_pos 4414 CRC32 0x89bcb330   Table_map: `replcrash`.`repl_innodb` mapped to number 308
# at 4414
#171201 23:00:32 server id 1323306  end_log_pos 4470 CRC32 0x80d6ed1a   Write_rows: table id 308 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
###   @1=4
###   @2='m1062-4'
###   @3='m1062-4'
# at 4470
#171201 23:01:58 server id 1323306  end_log_pos 4501 CRC32 0xdc2e8ab8   Xid = 1133
COMMIT/*!*/;
==================== repl_innodb表操作id=123、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.000003
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 4
#171201 22:54:07 server id 1333306  end_log_pos 123 CRC32 0xb5872a85    Start: binlog v 4, server v 5.7.19-log created 171201 22:54:07 at startup
# Warning: this binlog is either in use or was not closed properly.
ROLLBACK/*!*/;
# at 123
#171201 22:54:08 server id 1333306  end_log_pos 154 CRC32 0x2f0d74be    Previous-GTIDs
# [empty]
# at 154
#171201 23:01:19 server id 1323306  end_log_pos 219 CRC32 0x227de897    Anonymous_GTID  last_committed=0        sequence_number=1       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 219
#171201 23:01:19 server id 1323306  end_log_pos 282 CRC32 0x9bd4c099    Query   thread_id=13    exec_time=322   error_code=0
SET TIMESTAMP=1512140479/*!*/;
SET @@session.pseudo_thread_id=13/*!*/;
SET @@session.foreign_key_checks=1, @@session.sql_auto_is_null=0, @@session.unique_checks=1, @@session.autocommit=1/*!*/;
SET @@session.sql_mode=524288/*!*/;
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的記錄,重復key進行update操作,Start ====================
BEGIN
/*!*/;
# at 282
#171201 23:01:19 server id 1323306  end_log_pos 347 CRC32 0xe221b9d8    Table_map: `replcrash`.`repl_myisam` mapped to number 124
# at 347
#171201 23:01:19 server id 1323306  end_log_pos 425 CRC32 0x32dc6ddc    Update_rows: table id 124 flags: STMT_END_F
### UPDATE `replcrash`.`repl_myisam`
### WHERE
###   @1=1
###   @2='s1062-1'
###   @3='s1062-1'
### SET
###   @1=1
###   @2='m1062-1'
###   @3='m1062-1'
# at 425
#171201 23:01:19 server id 1323306  end_log_pos 489 CRC32 0x8e56c4de    Query   thread_id=13    exec_time=322   error_code=0
SET TIMESTAMP=1512140479/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
COMMIT
/*!*/;
# at 489
==================== repl_myisam表寫入id=1的記錄,重復key進行update操作,End ====================

==================== repl_myisam表更新id=2、刪除id=3的記錄Start ====================
update/delete 在從庫沒找到記錄,沒有做任何處理,相當於skip
==================== repl_myisam表更新id=2、刪除id=3的記錄End ====================

#171201 23:01:52 server id 1323306  end_log_pos 554 CRC32 0x0401a98f    Anonymous_GTID  last_committed=1        sequence_number=2       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 554
#171201 23:01:52 server id 1323306  end_log_pos 617 CRC32 0xb8743fdf    Query   thread_id=13    exec_time=289   error_code=0
SET TIMESTAMP=1512140512/*!*/;
SET @@session.sql_mode=524288/*!*/;
==================== repl_myisam表寫入id=4的記錄Start ====================
BEGIN
/*!*/;
# at 617
#171201 23:01:52 server id 1323306  end_log_pos 682 CRC32 0x8dc365d7    Table_map: `replcrash`.`repl_myisam` mapped to number 124
# at 682
#171201 23:01:52 server id 1323306  end_log_pos 738 CRC32 0x773e7fc0    Write_rows: table id 124 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_myisam`
### SET
###   @1=4
###   @2='m1062-4'
###   @3='m1062-4'
# at 738
#171201 23:01:52 server id 1323306  end_log_pos 802 CRC32 0x221bf96b    Query   thread_id=13    exec_time=289   error_code=0
SET TIMESTAMP=1512140512/*!*/;
SET @@session.sql_mode=1436549152/*!*/;
COMMIT
/*!*/;
# at 802
==================== repl_myisam表寫入id=4的記錄End ====================
#171201 23:00:32 server id 1323306  end_log_pos 867 CRC32 0x4e47e1fc    Anonymous_GTID  last_committed=2        sequence_number=3       rbr_only=yes
/*!50718 SET TRANSACTION ISOLATION LEVEL READ COMMITTED*//*!*/;
SET @@SESSION.GTID_NEXT= 'ANONYMOUS'/*!*/;
# at 867
#171201 23:00:04 server id 1323306  end_log_pos 930 CRC32 0x081b8094    Query   thread_id=13    exec_time=397   error_code=0
SET TIMESTAMP=1512140404/*!*/;
SET @@session.sql_mode=524288/*!*/;
==================== repl_innodb表操作id=1、4的記錄(2、3被skip),在一個事務中Start ====================
BEGIN
/*!*/;
# at 930
#171201 23:00:04 server id 1323306  end_log_pos 995 CRC32 0x9797a0bd    Table_map: `replcrash`.`repl_innodb` mapped to number 123
# at 995
#171201 23:00:04 server id 1323306  end_log_pos 1073 CRC32 0xe457ab20   Update_rows: table id 123 flags: STMT_END_F
### UPDATE `replcrash`.`repl_innodb`
### WHERE
###   @1=1
###   @2='s1062-1'
###   @3='s1062-1'
### SET
###   @1=1
###   @2='m1062-1'
###   @3='m1062-1'
# at 1073
#171201 23:00:32 server id 1323306  end_log_pos 1138 CRC32 0x6fd579ab   Table_map: `replcrash`.`repl_innodb` mapped to number 123
# at 1138
#171201 23:00:32 server id 1323306  end_log_pos 1194 CRC32 0x6c5678ef   Write_rows: table id 123 flags: STMT_END_F
### INSERT INTO `replcrash`.`repl_innodb`
### SET
###   @1=4
###   @2='m1062-4'
###   @3='m1062-4'
# at 1194
#171201 23:00:32 server id 1323306  end_log_pos 1225 CRC32 0x594d2812   Xid = 45
COMMIT/*!*/;
==================== repl_innodb表操作id=1、4的記錄(2、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)場景中主從數據不一致,復制狀態正常
遇到復制中斷第一時間要想怎么滿足這個復制,而不是去跳過這個事務(・ω・)


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM