MySQL複製跳過錯誤--slave_skip_errors、sql_slave_skip_counter、slave_exec_mode

lhrbest發表於2019-07-22

MySQL主從複製中的跳過錯誤處理引數--slave_skip_errors、sql_slave_skip_counter、slave_exec_mode



跳過複製錯誤——slave_skip_errors、slave_exec_mode

跳過複製錯誤——sql_slave_skip_counter




1 簡介

    mysql在主從複製過程中,由於各種的原因,從伺服器可能會遇到執行BINLOG中的SQL出錯的情況,在預設情況下,伺服器會停止複製程式,不再進行同步,等到使用者自行來處理。

    slave-skip-errors的作用就是用來定義複製過程中從伺服器可以自動跳過的錯誤號,當複製過程中遇到定義的錯誤號,就可以自動跳過,直接執行後面的SQL語句。

2 官方參考



    slave_skip_errors選項有四個可用值,分別為:off,all,ErorCode,ddl_exist_errors。

     預設情況下該引數值是off,我們可以列出具體的error code,也可以選擇all,mysql5.6及MySQL Cluster NDB 7.3以及後續版本增加了引數ddl_exist_errors,該引數包含一系列error code(1007,1008,1050,1051,1054,1060,1061,1068,1094,1146)

    一些error code代表的錯誤如下:

    1007:資料庫已存在,建立資料庫失敗

    1008:資料庫不存在,刪除資料庫失敗

    1050:資料表已存在,建立資料表失敗

    1051:資料表不存在,刪除資料表失敗

    1054:欄位不存在,或程式檔案跟資料庫有衝突

    1060:欄位重複,導致無法插入

    1061:重複鍵名

    1068:定義了多個主鍵

    1094:位置執行緒ID

    1146:資料表缺失,請恢復資料庫

    1053:複製過程中主伺服器當機

    1062:主鍵衝突 Duplicate entry '%s' for key %d


 my.cnf中的寫法:

slave_skip_errors=1062,1053  

slave_skip_errors=all  

slave_skip_errors=ddl_exist_errors  

  

  作為mysql啟動引數的寫法:

--slave-skip-errors=1062,1053  

--slave-skip-errors=all  

--slave-skip-errors=ddl_exist_errors  

    

從資料庫中檢視該引數的值:

mysql> show variables like 'slave_skip%';  

+-------------------+-------+  

| Variable_name     | Value |  

+-------------------+-------+  

| slave_skip_errors | 1007  |  

+-------------------+-------+  


3 舉例分析

    3.1 測試說明

    配置好mysql主從同步,然後在從上寫入資料,造成主從不一致。

    3.2 準備測試表結構

    在主機上建立表:

create table replication (c1 int not null primary key, c2 varchar(10));  

    3.3 準備測試資料

    在主機上插入基礎資料

mysql> insert into replication values (1, 'test1');  

mysql> insert into replication values (2, 'test2');  

    此時,主機從機replication表裡面都有兩條記錄

    3.4 開始測試

    從機插入一條記錄

mysql> insert into replication values (3, 'test3');  

    然後在主機上執行相同的操作

mysql> insert into replication values (3, 'test3');  

    在從機上檢視複製狀態

mysql> show slave status \G  

*************************** 1. row ***************************  

               Slave_IO_State: Waiting for master to send event  

                  Master_Host: 192.168.1.222  

                  Master_User: repl  

                  Master_Port: 3306  

                Connect_Retry: 60  

              Master_Log_File: mysql-bin.000003  

          Read_Master_Log_Pos: 16700  

               Relay_Log_File: mysql-relay-bin.000003  

                Relay_Log_Pos: 16595  

        Relay_Master_Log_File: mysql-bin.000003  

             Slave_IO_Running: Yes  

            Slave_SQL_Running: No  

              Replicate_Do_DB:   

          Replicate_Ignore_DB:   

           Replicate_Do_Table:   

       Replicate_Ignore_Table: mysql.ibbackup_binlog_marker  

      Replicate_Wild_Do_Table:   

  Replicate_Wild_Ignore_Table: mysql.backup_%  

                   Last_Errno: 1062  

                   Last_Error: Error 'Duplicate entry '3' for key 'PRIMARY'' on query. Default database: 'test'. Query: 'insert into replication values (3, 'test3')'  

                 Skip_Counter: 0  

          Exec_Master_Log_Pos: 16425  

              Relay_Log_Space: 17544  

    可以看到:sql執行緒已經停止工作 Slave_SQL_Running: No

                        錯誤號為:Last_Errno: 1062

                        錯誤資訊為:Last_Error: Error 'Duplicate entry '3' for key 'PRIMARY'' on query. Default database: 'test'. Query: 'insert into replication values (3, 'test3')'

    如果我們在my.cnf中加入如下選項,則可跳過此錯誤,資料同步繼續進行。

[mysqld]  

slave_skip_errors=1062  

    具體測試方法同上,大家可自己驗證。

4 從backup恢復時從機複製出錯的一些解釋


    mysql企業版備份工具meb提供線上熱備功能,如果在備份過程中執行ddl操作,從機需要從主機的備份恢復時可能會異常,從而導致從機同步資料失敗。原因是從機恢復時需要先從備份檔案恢復(包含備份過程中執行的ddl語句),

同步時不是從全備後的最後一個位置同步,而是從ddl的上個位置同步,如果再次執行該ddl語句在從機上不會造成衝突,

則同步繼續,如果會造成衝突,同步終止。解決此衝突的辦法是在my.cnf檔案中加入一行

[mysqld]  

slave_skip_errors=ddl_exist_errors  

5 注意事項

    5.1 該引數為全域性靜態引數,不能動態調整,可在my.cnf中加入該引數列表後重啟mysql伺服器生效。

    5.2 必須注意的是,啟動這個引數,如果處理不當,很可能造成主從資料庫的資料不同步,在應用中需要根據實際情況,如果對資料完整性要求不是很嚴格,那麼這個選項確實可以減輕維護的成本

****************************************************************************************


sql_slave_skip_counter 介紹:

摘自MySQL官方的解釋( 強烈建議閱讀英文原文 。中文版,是筆者自己的理解,只能說仁者見仁)

SET GLOBAL sql_slave_skip_counter Syntax:
        SET GLOBAL sql_slave_skip_counter = N
This statement skips the next N events from the master. This is useful for recovering from replication stops caused by a statement.
        跳過N個events。注意:以event為單位,而不是以事務為單位,只有在由單條語句組成的事務時,兩者才等價。
        如:一個事務由多個EVENT組成,BEGIN;INSERT;UPDATE;DELETE;COMMOIT; 這種情況下,兩者絕不相等
This statement is valid only when the slave threads are not running. Otherwise, it produces an error.

When using this statement, it is important to understand that the binary log is actually organized as a sequence of groups known as event groups. Each event group consists of a sequence of events.

For transactional tables, an event group corresponds to a transaction.
        對於事務表,一個event group對應一個事務
or nontransactional tables, an event group corresponds to a single SQL statement. 
        對於非事務表,一個event group對應一條SQL
When you use SET GLOBAL sql_slave_skip_counter to skip events and the result is in the middle of a group, the slave continues to skip events until it reaches the end of the group. Execution then starts with the next event group
        當你跳過event的時候,如果N的值,處於event group之中,那麼slave會繼續跳過event,直至跳過這個event group,從下一個event group開始


對於事務表使用 sql_slave_skip_counter 的情況:


1、跳過1032複製錯誤(update/delete error)

跳過由單條SQL組成的事務:


在Slave主機上人為的刪除兩條資料:

DELETE FROM `edusoho_e`.`t1` WHERE `id` = '9'; 
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '11'; 


而Master在變更上述兩條記錄的時候會報錯,導致複製中斷:

INSERT INTO `edusoho_e`.`t1` (`xname`, `address`, `hobby`) VALUES ('孫權', '吳國', '妹妹'); 
UPDATE `edusoho_e`.`t1` SET xname='遊戲' WHERE id=7;
UPDATE `edusoho_e`.`t1` SET age=40 WHERE id=11;     #報錯
DELETE FROM `edusoho_e`.`t1` WHERE age=40;             #報錯
INSERT INTO `edusoho_e`.`t1` (`xname`, `address`, `hobby`) VALUES ('曹丕', '魏國', '甄姬');
DELETE FROM `edusoho_e`.`t1` WHERE id=1;
UPDATE `edusoho_e`.`t1` SET hobby='Games' WHERE id=3; 


在Slave檢視主從複製狀態時,就會發現報錯資訊:

mysql> show slave status\G;
*************************** 1. row ***************************
Read_Master_Log_Pos: 2176
Exec_Master_Log_Pos:  874
Last_Errno: 1032
Last_Error: Could not execute  Update_rows  event on table edusoho_e.t1; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000002, end_log_pos 1127
Slave_IO_Running: Yes
Slave_SQL_Running: No


在Master主機上檢視position做了什麼操作:

mysql> show binlog events in 'mysql-bin.000002' from 874;
+------------------+------+-------------+-----------+-------------+---------------------------------+
| Log_name         | Pos  | Event_type  | Server_id | End_log_pos | Info                            |
+------------------+------+-------------+-----------+-------------+---------------------------------+
| mysql-bin.000002 |   874  | Query       |         2 |         956 | BEGIN                           |
| mysql-bin.000002 |  956 | Table_map   |         2 |        1017 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 1017 | Update_rows |         2 |        1127 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 1127 | Xid         |         2 |        1158 | COMMIT /* xid=437 */            |
| mysql-bin.000002 | 1158 | Query       |         2 |        1240 | BEGIN                           |
| mysql-bin.000002 | 1240 | Table_map   |         2 |        1301 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 1301 | Delete_rows |         2 |        1407 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 1407 | Xid         |         2 |        1438 | COMMIT /* xid=446 */            |
| mysql-bin.000002 | 1438 | Query       |         2 |        1520 | BEGIN                           |
| mysql-bin.000002 | 1520 | Table_map   |         2 |        1581 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 1581 | Write_rows  |         2 |        1644 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 1644 | Xid         |         2 |        1675 | COMMIT /* xid=455 */            |
| mysql-bin.000002 | 1675 | Query       |         2 |        1757 | BEGIN                           |
| mysql-bin.000002 | 1757 | Table_map   |         2 |        1818 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 1818 | Delete_rows |         2 |        1880 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 1880 | Xid         |         2 |        1911 | COMMIT /* xid=464 */            |
| mysql-bin.000002 | 1911 | Query       |         2 |        1993 | BEGIN                           |
| mysql-bin.000002 | 1993 | Table_map   |         2 |        2054 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 2054 | Update_rows |         2 |        2145 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 2145 | Xid         |         2 |        2176 | COMMIT /* xid=473 */            |
+------------------+------+-------------+-----------+-------------+---------------------------------+


在Slave跳過第一個 Update_rows event 複製報錯:

mysql>  set global sql_slave_skip_counter=1;
mysql>  start slave sql_thread;
mysql> show slave status\G;
Slave_IO_Running: Yes
Slave_SQL_Running: No
Exec_Master_Log_Pos:  1158
Last_SQL_Errno: 1032
Last_SQL_Error: Could not execute  Delete_rows  event on table edusoho_e.t1; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000002, end_log_pos 1407


成功跳過第一個events group


在Slave繼續跳過第二個 Delete_rows event 複製報錯:

mysql> set global sql_slave_skip_counter=1;
mysql> start slave sql_thread;
mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_SQL_Errno: 0
Last_SQL_Error: 


成功跳過第二個 events group


注意:

雖然主從複製出現的故障成功跳過了,但只是暫時恢復了正常的主從複製狀態,需要儘快的對Slave缺失的資料進行補齊,不然Master對Slave不存在的資料做的變更,仍然會重複導致主從複製故障,筆者覺得如果你的資料量差異不是太大的話,可以考慮使用 pt-table-checksum pt-table-sync 工具進行恢復,如果你的資料量很大且資料差異很多,還是建議重做Slave較好,因為使用工具會鎖表,會對線上業務造成一定的影響,具體情況,請自行考量。


跳過由多條SQL(event)組成的事務:

在Slave主機上人為的刪除一條資料:

DELETE FROM `edusoho_e`.`t1` WHERE `id` = '7'; 


在Master主機上產生一個由多條SQL組成的事務:

BEGIN;
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '7'; 
INSERT INTO `edusoho_e`.`t1` (`xname`, `address`, `hobby`) VALUES ('懶死', '不知道', '吃了睡睡了吃'); 
COMMIT;


因為Slave主機上已經刪除id=7的資料,在Slave檢視主從複製狀態時,就會發現報錯資訊:

mysql> show slave status\G;
*************************** 1. row ***************************
Read_Master_Log_Pos: 7219
Exec_Master_Log_Pos:  6840
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_Errno: 1032
Last_Error: Could not execute  Delete_rows  event on table edusoho_e.t1; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000002, end_log_pos 7049


在Master主機上檢視position做了什麼操作:

mysql> show binlog events in 'mysql-bin.000002' from 6840;
+------------------+------+-------------+-----------+-------------+---------------------------------+
| Log_name         | Pos  | Event_type  | Server_id | End_log_pos | Info                            |
+------------------+------+-------------+-----------+-------------+---------------------------------+
| mysql-bin.000002 | 6840 | Query       |         2 |        6922 |  BEGIN                            |
| mysql-bin.000002 | 6922 | Table_map   |         2 |        6983 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 6983 | Delete_rows |         2 |        7049 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 7049 | Table_map   |         2 |        7110 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 7110 | Write_rows  |         2 |        7188 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 7188 | Xid         |         2 |         7219  COMMIT  /* xid=825 */            |
+------------------+------+-------------+-----------+-------------+---------------------------------+


可以看到,這個事務是由兩個SQL(event)組成的


如果使用 sql_slave_skip_counter=N 跳過由多條SQL組成的事務會怎樣呢?

mysql> set global sql_slave_skip_counter=1;
mysql> start slave sql_thread;
mysql> show slave status\G;
*************************** 1. row ***************************
Read_Master_Log_Pos: 7219
Exec_Master_Log_Pos:  7219
Slave_IO_Running: Yes
Slave_SQL_Running: Yes
Last_Errno: 0
Last_Error:


發現問題沒有 ,在使用sql_slave_skip_counter跳過由多條SQL(event)組成的事務時,從在Master上執行的 show binlog events 可以看到,如果只是跳過出報錯SQL語句,那麼 Exec_Master_Log_Pos 值應該為7110,但是現在為7219,說明將整個event group跳過了,但是7110的SQL資料是我們需要的,所以,和單條SQL組成的事務一樣,主從複製狀態雖然恢復,但是資料仍處於不一致狀態,要抓緊時間補齊資料或重做Slave


2、 由多條SQL(event)組成的事務時,僅跳過一個event,而不是一個event group:

在Slave主機上人為的刪除一條資料:

DELETE FROM `edusoho_e`.`t1` WHERE `id` = '17'; 


在Master主機上產生一個由多條SQL組成的事務:

BEGIN;
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '17';
INSERT INTO `edusoho_e`.`t1` (`xname`, `address`, `hobby`) VALUES ('我是誰', '不知道', '吃了睡睡了吃');
COMMIT;


因為Slave主機上已經刪除id=17的資料,在Slave檢視主從複製狀態時,就會發現報錯資訊:

Exec_Master_Log_Pos:  120

Slave_IO_Running: Yes
Slave_SQL_Running: No

Last_Errno: 1032
Last_Error: Could not execute  Delete_rows  event on table edusoho_e.t1; Can't find record in 't1', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log mysql-bin.000004, end_log_pos 341


在Master主機上檢視position做了什麼操作:

mysqlbinlog -v --base64-output=decode --start-position=120 mysql-bin.000004
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=1*/;
/*!40019 SET @@session.max_insert_delayed_threads=0*/;
/*!50003 SET @OLD_COMPLETION_TYPE=@@COMPLETION_TYPE,COMPLETION_TYPE=0*/;
DELIMITER /*!*/;
# at 120
#190507 13:52:05 server id 2  end_log_pos 202 CRC32 0x0ca0c280     Query    thread_id=3    exec_time=0    error_code=0
SET TIMESTAMP=1557208325/*!*/;
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=1073741824/*!*/;
SET @@session.auto_increment_increment=2, @@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/*!*/;
BEGIN
/*!*/;
# at 202
#190507 13:52:05 server id 2  end_log_pos 263 CRC32 0x20d2e89d     Table_map: `edusoho_e`.`t1` mapped to number 216
# at 263
#190507 13:52:05 server id 2  end_log_pos 341 CRC32 0xbec6fd45     Delete_rows: table id 216 flags: STMT_END_F
### DELETE FROM `edusoho_e`.`t1`
### WHERE
###   @1=17
###   @2='懶死'
###   @3='不知道'
###   @4=1
###   @5='吃了睡睡了吃'
###   @6=18

# at 341
#190507 13:52:05 server id 2  end_log_pos 402 CRC32 0xa37bc5c9     Table_map: `edusoho_e`.`t1` mapped to number 216
# at 402
#190507 13:52:05 server id 2  end_log_pos 483 CRC32 0x0d774707     Write_rows: table id 216 flags: STMT_END_F
### INSERT INTO `edusoho_e`.`t1`
### SET
###   @1=21
###   @2='我是誰'
###   @3='不知道'
###   @4=1
###   @5='吃了睡睡了吃'
###   @6=18
# at 483
#190507 13:52:05 server id 2  end_log_pos 514 CRC32 0x8c333b30     Xid = 411
COMMIT /*!*/;
DELIMITER ;
# End of log file
ROLLBACK /* added by mysqlbinlog */;
/*!50003 SET COMPLETION_TYPE=@OLD_COMPLETION_TYPE*/;
/*!50530 SET @@SESSION.PSEUDO_SLAVE_MODE=0*/;

可以看到,綠色的部分就是我們需要跳過的,而第二個event是需要我們保留的

這個時候,就需要用到 slave_exec_mode 這個變數了,至於slave_exec_mode詳細介紹,還是請參考MySQL官網資料


mysql> set global slave_exec_mode='IDEMPOTENT';
mysql> start slave sql_thread;
mysql> show slave status\G;
*************************** 1. row ***************************

Slave_IO_Running: Yes
Slave_SQL_Running: Yes

Exec_Master_Log_Pos: 514


去Slave上edusoho_e.t1表上檢視,資料id=21的資料已經過去了,此時,資料處於一致性狀態


3、 跳過主鍵衝突1062錯誤(Duplicate entry):

在Slave主鍵上先插入一條id值:

INSERT INTO `edusoho_e`.`t1` (`id`,`xname`, `address`, `hobby`, `age`) VALUES (19,'小玩子', '明朝', '皇后', '25'); 


因為Slave已經佔用了Master要自動產生的主鍵值id=19,所以Slave主機會報錯:

INSERT INTO `edusoho_e`.`t1` (`id`,`xname`, `address`, `hobby`, `age`) VALUES (19,'朱棣', '明朝', '皇帝', '36'); 


檢視Slave主從複製狀態發現已經發生了主從複製報錯:

mysql> show slave status\G;
*************************** 1. row ***************************
Slave_IO_Running: Yes
Slave_SQL_Running: No
Last_Errno: 1062
Last_Error: Could not execute Write_rows event on table edusoho_e.t1;  Duplicate entry  '19' for key 'PRIMARY', Error_code: 1062; handler error HA_ERR_FOUND_DUPP_KEY; the event's master log mysql-bin.000002, end_log_pos 7425
Exec_Master_Log_Pos:  7219


檢視Master binlog:

mysql> show binlog events in 'mysql-bin.000002' from 7219;
+------------------+------+------------+-----------+-------------+---------------------------------+
| Log_name         | Pos  | Event_type | Server_id | End_log_pos | Info                            |
+------------------+------+------------+-----------+-------------+---------------------------------+
| mysql-bin.000002 | 7219 | Query      |         2 |        7301 | BEGIN                           |
| mysql-bin.000002 | 7301 | Table_map  |         2 |        7362 | table_id: 213 (edusoho_e.t1)    |
| mysql-bin.000002 | 7362 | Write_rows |         2 |        7425 | table_id: 213 flags: STMT_END_F |
| mysql-bin.000002 | 7425 | Xid        |         2 |        7456 | COMMIT /* xid=893 */            |
+------------------+------+------------+-----------+-------------+---------------------------------+


思考:

因為Slave這條資料已經存在,如果在Slave主機上把這條資料刪除了,Slave會不會直接同步過來?(答案是:不會。需要重啟Slave thread):

DELETE FROM `edusoho_e`.`t1` WHERE `id` = '19'; 
mysql> stop slave;
mysql> start slave user='repliter' password='123456';

驗證的時候,發現資料已經同步過去了


題外:

以上是筆者對於單條SQL組成的事務、多條SQL組成的事務,及在這些單/多條SQL組成的事務下,人為設定的1032和1062複製錯誤和解決方法,還有sql_slave_skip_counter和slave_exec_mode各自的用法和跳過的範圍,當然了, 筆者呢,做的只是線上應用前的部署測試,並沒有經過任何的實戰檢測。一方面,僅為廣大同行做個參考;另一方面,記錄筆者自己的心得和針對問題解決的思路做個總結,當問題真正發生的時候,有個方向可以進行參考,而不至於手忙腳亂,不知所措,所以,對其中有誤之處和理解不到位的地方,望請下方留言指正,不勝感激!

還有,筆者做的,只是針對事務表,做的 sql_slave_skip_counter和slave_exec_mode測試,對於非事務表, sql_slave_skip_counter和slave_exec_mode用途會稍有不同,請自行百度吧。


slave_exec_mode=IDEMPOTENT 在MySQL複製環境中是個很有用的引數:只要在備機執行set global slave_exec_mode=IDEMPOTENT ,備機的sql thread就執行在冥等模式下,可以讓備機在insert主鍵、唯一鍵衝突,update、delete值未找到錯誤發生時不斷開復制而保持冥等性(當即生效,連slave的sql執行緒都不用重啟喲);而類似sql_slave_skip_counter=N和slave-skip-errors = N 這樣的粗暴跳過錯誤方法可能破壞主備一致性。但官方文件的描述很簡潔,我一直好奇slave_exec_mode=IDEMPOTENT 是如何在複製出錯時保持一致性的--譬如主鍵衝突時是簡單跳過還是覆寫,今天在Percona 5.7下做了個實驗(binlog是row格式),實驗過程就省略了,直接總結如下:
1.insert場景
此時insert into語句在備機的效果就跟replace into一樣,但卻並不是把insert into轉換成replace into來執行,分兩種情況:
a.MySQL配置成autocommit,直接一條insert into ...
如這樣的insert
insert into test set c1='a',c2='b';
此時insert into語句在備機執行時假如遇到主鍵衝突就先轉化為delete再insert
delete from test where c1='old_value' and c2='old_value';   
insert into test set c1='a',c2='b';   
假如遇到非主鍵的唯一鍵衝突就轉換為update
update test set set c1='a',c2='b' where c1='old_value' and c2='old_value';
b.當顯示開始事務時(begin...insert into...commit;)
如這樣的sql
begin;   
...... 
insert into test set c1='a',c2='b';   
...... 
commit;   
此時begin...commit裡的insert into語句在備機執行時假如遇到主鍵衝突、唯一鍵衝突都是先轉化為delete再insert
begin;   
...... 
delete from test where c1='old_value' and c2='old_value';   
insert into test set c1='a',c2='b';   
...... 
commit;   
2.update場景
當備機不存在要更新的記錄,這條update跳過不執行
3.delete場景 
同update場景一樣,備機跳過此delete啥也不幹
注意:使用冥等模式時表要有主鍵
冥等模式並不是萬能的,除了不能對DDL操作冥等,對欄位長度不同導致的錯誤也不是冥等(譬如主機一個欄位是char(20)而備機是char(10)),還有一個限制就是表有主鍵才會對insert的冥等設定有效:因為insert的冥等行為是透過主鍵來判斷備機是否有重複值從而產生覆寫操作,如果表沒有主鍵,則備機即使設了冥等也可能會比主機多重複資料。


slave_exec_mode設定可以跳過1032(記錄沒有找到)和1062(主鍵重複)錯誤,並記錄到錯誤日誌中。
slave_exec_mode和slave_skip_errors作用是一樣的,只是slave_exec_mode可以線上動態設定。slave_skip_errors必須新增到配置檔案中,重啟生效。
備庫
mysql> select * from testdb1.student;
+------+------+-------+-------+
| id   | name | class | score |
+------+------+-------+-------+
|    1 | a    | 1     |    45 |
|    2 | b    | 1     |    46 |
|    3 | c    | 2     |    89 |
|    4 | d    | 2     |    90 |
|    5 | e    | 3     |    67 |
|    6 | f    | 3     |    87 |
|    7 | g    | 4     |    77 |
|    8 | h    | 4     |    91 |
+------+------+-------+-------+
8 rows in set (0.00 sec)
mysql> delete from testdb1.student where id >5;
Query OK, 3 rows affected (0.00 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
#修改引數之前
主庫master
mysql>  delete from testdb1.student where id >7;
Query OK, 1 row affected (0.00 sec)
備庫檢視狀態
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.56.91
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: ray-bin.000008
          Read_Master_Log_Pos: 1272
               Relay_Log_File: ray-relay-bin.000003
                Relay_Log_Pos: 1226
        Relay_Master_Log_File: ray-bin.000008
             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: 1032
                   Last_Error: Could not execute Delete_rows event on table testdb1.student; Can't find record in 'student', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log ray-bin.000008, end_log_pos 1241
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1065
              Relay_Log_Space: 1957
              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: 1032
               Last_SQL_Error: Could not execute Delete_rows event on table testdb1.student; Can't find record in 'student', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log ray-bin.000008, end_log_pos 1241
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 2
                  Master_UUID: 840f94e0-8ea0-11e5-af92-080027a94012
             Master_Info_File: /data/3307/data/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: 151126 12:42:37
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
1 row in set (0.00 sec)
mysql> stop slave;
Query OK, 0 rows affected (0.78 sec)
mysql> set global sql_slave_skip_counter=1;
Query OK, 0 rows affected (0.01 sec)
mysql> start slave;
Query OK, 0 rows affected (0.33 sec)
#修改備庫引數
mysql> show variables like '%slave_exec_mode%';
+-----------------+--------+
| Variable_name   | Value  |
+-----------------+--------+
| slave_exec_mode | STRICT |
+-----------------+--------+
1 row in set (0.00 sec)
mysql> set global slave_exec_mode=idempotent;
Query OK, 0 rows affected (0.00 sec)
mysql> show variables like '%slave_exec_mode%';
+-----------------+------------+
| Variable_name   | Value      |
+-----------------+------------+
| slave_exec_mode | IDEMPOTENT |
+-----------------+------------+
1 row in set (0.00 sec)
主庫刪除資料
mysql>  delete from testdb1.student where id >6;
Query OK, 1 row affected (0.01 sec)
mysql> commit;
Query OK, 0 rows affected (0.00 sec)
備庫檢視狀態和錯誤日誌
mysql> show slave status\G
*************************** 1. row ***************************
               Slave_IO_State: Waiting for master to send event
                  Master_Host: 192.168.56.91
                  Master_User: rep
                  Master_Port: 3306
                Connect_Retry: 60
              Master_Log_File: ray-bin.000008
          Read_Master_Log_Pos: 1479
               Relay_Log_File: ray-relay-bin.000004
                Relay_Log_Pos: 488
        Relay_Master_Log_File: ray-bin.000008
             Slave_IO_Running: Yes
            Slave_SQL_Running: Yes
              Replicate_Do_DB:
          Replicate_Ignore_DB:
           Replicate_Do_Table:
       Replicate_Ignore_Table:
      Replicate_Wild_Do_Table:
  Replicate_Wild_Ignore_Table:
                   Last_Errno: 0
                   Last_Error:
                 Skip_Counter: 0
          Exec_Master_Log_Pos: 1479
              Relay_Log_Space: 1972
              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: 0
Master_SSL_Verify_Server_Cert: No
                Last_IO_Errno: 0
                Last_IO_Error:
               Last_SQL_Errno: 0
               Last_SQL_Error:
  Replicate_Ignore_Server_Ids:
             Master_Server_Id: 2
                  Master_UUID: 840f94e0-8ea0-11e5-af92-080027a94012
             Master_Info_File: /data/3307/data/master.info
                    SQL_Delay: 0
          SQL_Remaining_Delay: NULL
      Slave_SQL_Running_State: Slave has read all relay log; waiting for the slave I/O thread to update it
           Master_Retry_Count: 86400
                  Master_Bind:
      Last_IO_Error_Timestamp:
     Last_SQL_Error_Timestamp:
               Master_SSL_Crl:
           Master_SSL_Crlpath:
           Retrieved_Gtid_Set:
            Executed_Gtid_Set:
                Auto_Position: 0
1 row in set (0.00 sec)
[root@ray ~]# tail -20f /data/3307/data/mysql_ray.err
2015-11-26 12:50:29 12127 [Warning] Slave SQL: Could not execute Delete_rows event on table testdb1.student; Can't find record in 'student', Error_code: 1032; handler error HA_ERR_END_OF_FILE; the event's master log ray-bin.000008, end_log_pos 1655, Error_code: 1032
注:pos可能對不上,因為擷取的問題,不必在意。







About Me

........................................................................................................................

● 本文作者:小麥苗,部分內容整理自網路,若有侵權請聯絡小麥苗刪除

● 本文在itpub、部落格園、CSDN和個人微 信公眾號( xiaomaimiaolhr )上有同步更新

● 本文itpub地址: http://blog.itpub.net/26736162

● 本文部落格園地址: http://www.cnblogs.com/lhrbest

● 本文CSDN地址: https://blog.csdn.net/lihuarongaini

● 本文pdf版、個人簡介及小麥苗雲盤地址: http://blog.itpub.net/26736162/viewspace-1624453/

● 資料庫筆試面試題庫及解答: http://blog.itpub.net/26736162/viewspace-2134706/

● DBA寶典今日頭條號地址:

........................................................................................................................

● QQ群號: 230161599 (滿) 、618766405

● 微 信群:可加我微 信,我拉大家進群,非誠勿擾

● 聯絡我請加QQ好友 646634621 ,註明新增緣由

● 於 2019-07-01 06:00 ~ 2019-07-31 24:00 在西安完成

● 最新修改時間:2019-07-01 06:00 ~ 2019-07-31 24:00

● 文章內容來源於小麥苗的學習筆記,部分整理自網路,若有侵權或不當之處還請諒解

● 版權所有,歡迎分享本文,轉載請保留出處

........................................................................................................................

小麥苗的微店

小麥苗出版的資料庫類叢書 http://blog.itpub.net/26736162/viewspace-2142121/

小麥苗OCP、OCM、高可用網路班 http://blog.itpub.net/26736162/viewspace-2148098/

小麥苗騰訊課堂主頁 https://lhr.ke.qq.com/

........................................................................................................................

使用 微 信客戶端 掃描下面的二維碼來關注小麥苗的微 信公眾號( xiaomaimiaolhr )及QQ群(DBA寶典)、新增小麥苗微 信, 學習最實用的資料庫技術。

........................................................................................................................

歡迎與我聯絡

 

 



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26736162/viewspace-2651331/,如需轉載,請註明出處,否則將追究法律責任。

相關文章