MySQL复制跳过错误--slave_skip_errors、sql_slave_skip_counter、slave_exec_mode
MySQL主從復(fù)制中的跳過錯誤處理參數(shù)--slave_skip_errors、sql_slave_skip_counter、slave_exec_mode
跳過復(fù)制錯誤——slave_skip_errors、slave_exec_mode
跳過復(fù)制錯誤——sql_slave_skip_counter
1 簡介
? ? mysql在主從復(fù)制過程中,由于各種的原因,從服務(wù)器可能會遇到執(zhí)行BINLOG中的SQL出錯的情況,在默認(rèn)情況下,服務(wù)器會停止復(fù)制進(jìn)程,不再進(jìn)行同步,等到用戶自行來處理。
? ? slave-skip-errors的作用就是用來定義復(fù)制過程中從服務(wù)器可以自動跳過的錯誤號,當(dāng)復(fù)制過程中遇到定義的錯誤號,就可以自動跳過,直接執(zhí)行后面的SQL語句。
2 官方參考
? ? slave_skip_errors選項有四個可用值,分別為:off,all,ErorCode,ddl_exist_errors。
? ? ?默認(rèn)情況下該參數(shù)值是off,我們可以列出具體的error code,也可以選擇all,mysql5.6及MySQL Cluster NDB 7.3以及后續(xù)版本增加了參數(shù)ddl_exist_errors,該參數(shù)包含一系列error code(1007,1008,1050,1051,1054,1060,1061,1068,1094,1146)
? ? 一些error code代表的錯誤如下:
? ? 1007:數(shù)據(jù)庫已存在,創(chuàng)建數(shù)據(jù)庫失敗
? ? 1008:數(shù)據(jù)庫不存在,刪除數(shù)據(jù)庫失敗
? ? 1050:數(shù)據(jù)表已存在,創(chuàng)建數(shù)據(jù)表失敗
? ? 1051:數(shù)據(jù)表不存在,刪除數(shù)據(jù)表失敗
? ? 1054:字段不存在,或程序文件跟數(shù)據(jù)庫有沖突
? ? 1060:字段重復(fù),導(dǎo)致無法插入
? ? 1061:重復(fù)鍵名
? ? 1068:定義了多個主鍵
? ? 1094:位置線程ID
? ? 1146:數(shù)據(jù)表缺失,請恢復(fù)數(shù)據(jù)庫
? ? 1053:復(fù)制過程中主服務(wù)器宕機(jī)
? ? 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啟動參數(shù)的寫法:
--slave-skip-errors=1062,1053??
--slave-skip-errors=all??
--slave-skip-errors=ddl_exist_errors??
? ??
從數(shù)據(jù)庫中查看該參數(shù)的值:
mysql> show variables like 'slave_skip%';??
+-------------------+-------+??
| Variable_name? ? ?| Value |??
+-------------------+-------+??
| slave_skip_errors | 1007? |??
+-------------------+-------+??
3 舉例分析
? ? 3.1 測試說明
? ? 配置好mysql主從同步,然后在從上寫入數(shù)據(jù),造成主從不一致。
? ? 3.2 準(zhǔn)備測試表結(jié)構(gòu)
? ? 在主機(jī)上創(chuàng)建表:
create table replication (c1 int not null primary key, c2 varchar(10));??
? ? 3.3 準(zhǔn)備測試數(shù)據(jù)
? ? 在主機(jī)上插入基礎(chǔ)數(shù)據(jù)
mysql> insert into replication values (1, 'test1');??
mysql> insert into replication values (2, 'test2');??
? ? 此時,主機(jī)從機(jī)replication表里面都有兩條記錄
? ? 3.4 開始測試
? ? 從機(jī)插入一條記錄
mysql> insert into replication values (3, 'test3');??
? ? 然后在主機(jī)上執(zhí)行相同的操作
mysql> insert into replication values (3, 'test3');??
? ? 在從機(jī)上查看復(fù)制狀態(tài)
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線程已經(jīng)停止工作 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中加入如下選項,則可跳過此錯誤,數(shù)據(jù)同步繼續(xù)進(jìn)行。
[mysqld]??
slave_skip_errors=1062??
? ? 具體測試方法同上,大家可自己驗證。
4 從backup恢復(fù)時從機(jī)復(fù)制出錯的一些解釋
? ? mysql企業(yè)版?zhèn)浞莨ぞ適eb提供在線熱備功能,如果在備份過程中執(zhí)行ddl操作,從機(jī)需要從主機(jī)的備份恢復(fù)時可能會異常,從而導(dǎo)致從機(jī)同步數(shù)據(jù)失敗。原因是從機(jī)恢復(fù)時需要先從備份文件恢復(fù)(包含備份過程中執(zhí)行的ddl語句),
同步時不是從全備后的最后一個位置同步,而是從ddl的上個位置同步,如果再次執(zhí)行該ddl語句在從機(jī)上不會造成沖突,
則同步繼續(xù),如果會造成沖突,同步終止。解決此沖突的辦法是在my.cnf文件中加入一行
[mysqld]??
slave_skip_errors=ddl_exist_errors??
5 注意事項
? ? 5.1 該參數(shù)為全局靜態(tài)參數(shù),不能動態(tài)調(diào)整,可在my.cnf中加入該參數(shù)列表后重啟mysql服務(wù)器生效。
? ? 5.2 必須注意的是,啟動這個參數(shù),如果處理不當(dāng),很可能造成主從數(shù)據(jù)庫的數(shù)據(jù)不同步,在應(yīng)用中需要根據(jù)實際情況,如果對數(shù)據(jù)完整性要求不是很嚴(yán)格,那么這個選項確實可以減輕維護(hù)的成本
****************************************************************************************
sql_slave_skip_counter 介紹:
摘自MySQL官方的解釋( 強(qiáng)烈建議閱讀英文原文 。中文版,是筆者自己的理解,只能說仁者見仁)
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為單位,而不是以事務(wù)為單位,只有在由單條語句組成的事務(wù)時,兩者才等價。
??????? 如:一個事務(wù)由多個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.
??? ????對于事務(wù)表,一個event group對應(yīng)一個事務(wù)
or nontransactional tables, an event group corresponds to a single SQL statement.?
??????? 對于非事務(wù)表,一個event group對應(yīng)一條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
??? ????當(dāng)你跳過event的時候,如果N的值,處于event group之中,那么slave會繼續(xù)跳過event,直至跳過這個event group,從下一個event group開始
對于事務(wù)表使用 sql_slave_skip_counter 的情況:
1、跳過1032復(fù)制錯誤(update/delete error)
跳過由單條SQL組成的事務(wù):
在Slave主機(jī)上人為的刪除兩條數(shù)據(jù):
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '9';?
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '11';?
而Master在變更上述兩條記錄的時候會報錯,導(dǎo)致復(fù)制中斷:
INSERT INTO `edusoho_e`.`t1` (`xname`, `address`, `hobby`) VALUES ('孫權(quán)', '吳國', '妹妹');?
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查看主從復(fù)制狀態(tài)時,就會發(fā)現(xiàn)報錯信息:
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主機(jī)上查看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 復(fù)制報錯:
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繼續(xù)跳過第二個 Delete_rows event 復(fù)制報錯:
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
注意:
雖然主從復(fù)制出現(xiàn)的故障成功跳過了,但只是暫時恢復(fù)了正常的主從復(fù)制狀態(tài),需要盡快的對Slave缺失的數(shù)據(jù)進(jìn)行補(bǔ)齊,不然Master對Slave不存在的數(shù)據(jù)做的變更,仍然會重復(fù)導(dǎo)致主從復(fù)制故障,筆者覺得如果你的數(shù)據(jù)量差異不是太大的話,可以考慮使用 pt-table-checksum 和 pt-table-sync 工具進(jìn)行恢復(fù),如果你的數(shù)據(jù)量很大且數(shù)據(jù)差異很多,還是建議重做Slave較好,因為使用工具會鎖表,會對線上業(yè)務(wù)造成一定的影響,具體情況,請自行考量。
跳過由多條SQL(event)組成的事務(wù):
在Slave主機(jī)上人為的刪除一條數(shù)據(jù):
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '7';?
在Master主機(jī)上產(chǎn)生一個由多條SQL組成的事務(wù):
BEGIN;
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '7';?
INSERT INTO `edusoho_e`.`t1` (`xname`, `address`, `hobby`) VALUES ('懶死', '不知道', '吃了睡睡了吃');?
COMMIT;
因為Slave主機(jī)上已經(jīng)刪除id=7的數(shù)據(jù),在Slave查看主從復(fù)制狀態(tài)時,就會發(fā)現(xiàn)報錯信息:
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主機(jī)上查看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 */??????????? |
+------------------+------+-------------+-----------+-------------+---------------------------------+
可以看到,這個事務(wù)是由兩個SQL(event)組成的
如果使用 sql_slave_skip_counter=N 跳過由多條SQL組成的事務(wù)會怎樣呢?
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:
發(fā)現(xiàn)問題沒有 ,在使用sql_slave_skip_counter跳過由多條SQL(event)組成的事務(wù)時,從在Master上執(zhí)行的 show binlog events 可以看到,如果只是跳過出報錯SQL語句,那么 Exec_Master_Log_Pos 值應(yīng)該為7110,但是現(xiàn)在為7219,說明將整個event group跳過了,但是7110的SQL數(shù)據(jù)是我們需要的,所以,和單條SQL組成的事務(wù)一樣,主從復(fù)制狀態(tài)雖然恢復(fù),但是數(shù)據(jù)仍處于不一致狀態(tài),要抓緊時間補(bǔ)齊數(shù)據(jù)或重做Slave
2、 由多條SQL(event)組成的事務(wù)時,僅跳過一個event,而不是一個event group:
在Slave主機(jī)上人為的刪除一條數(shù)據(jù):
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '17';?
在Master主機(jī)上產(chǎn)生一個由多條SQL組成的事務(wù):
BEGIN;
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '17';
INSERT INTO `edusoho_e`.`t1` (`xname`, `address`, `hobby`) VALUES ('我是誰', '不知道', '吃了睡睡了吃');
COMMIT;
因為Slave主機(jī)上已經(jīng)刪除id=17的數(shù)據(jù),在Slave查看主從復(fù)制狀態(tài)時,就會發(fā)現(xiàn)報錯信息:
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主機(jī)上查看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詳細(xì)介紹,還是請參考MySQL官網(wǎng)資料
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表上查看,數(shù)據(jù)id=21的數(shù)據(jù)已經(jīng)過去了,此時,數(shù)據(jù)處于一致性狀態(tài)
3、 跳過主鍵沖突1062錯誤(Duplicate entry):
在Slave主鍵上先插入一條id值:
INSERT INTO `edusoho_e`.`t1` (`id`,`xname`, `address`, `hobby`, `age`) VALUES (19,'小玩子', '明朝', '皇后', '25');?
因為Slave已經(jīng)占用了Master要自動產(chǎn)生的主鍵值id=19,所以Slave主機(jī)會報錯:
INSERT INTO `edusoho_e`.`t1` (`id`,`xname`, `address`, `hobby`, `age`) VALUES (19,'朱棣', '明朝', '皇帝', '36');?
查看Slave主從復(fù)制狀態(tài)發(fā)現(xiàn)已經(jīng)發(fā)生了主從復(fù)制報錯:
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這條數(shù)據(jù)已經(jīng)存在,如果在Slave主機(jī)上把這條數(shù)據(jù)刪除了,Slave會不會直接同步過來?(答案是:不會。需要重啟Slave thread):
DELETE FROM `edusoho_e`.`t1` WHERE `id` = '19';?
mysql> stop slave;
mysql> start slave user='repliter' password='123456';
驗證的時候,發(fā)現(xiàn)數(shù)據(jù)已經(jīng)同步過去了
題外:
以上是筆者對于單條SQL組成的事務(wù)、多條SQL組成的事務(wù),及在這些單/多條SQL組成的事務(wù)下,人為設(shè)置的1032和1062復(fù)制錯誤和解決方法,還有sql_slave_skip_counter和slave_exec_mode各自的用法和跳過的范圍,當(dāng)然了, 筆者呢,做的只是線上應(yīng)用前的部署測試,并沒有經(jīng)過任何的實戰(zhàn)檢測。一方面,僅為廣大同行做個參考;另一方面,記錄筆者自己的心得和針對問題解決的思路做個總結(jié),當(dāng)問題真正發(fā)生的時候,有個方向可以進(jìn)行參考,而不至于手忙腳亂,不知所措,所以,對其中有誤之處和理解不到位的地方,望請下方留言指正,不勝感激!
還有,筆者做的,只是針對事務(wù)表,做的 sql_slave_skip_counter和slave_exec_mode測試,對于非事務(wù)表, sql_slave_skip_counter和slave_exec_mode用途會稍有不同,請自行百度吧。
slave_exec_mode=IDEMPOTENT?在MySQL復(fù)制環(huán)境中是個很有用的參數(shù):只要在備機(jī)運(yùn)行set?global?slave_exec_mode=IDEMPOTENT?,備機(jī)的sql?thread就運(yùn)行在冥等模式下,可以讓備機(jī)在insert主鍵、唯一鍵沖突,update、delete值未找到錯誤發(fā)生時不斷開復(fù)制而保持冥等性(當(dāng)即生效,連slave的sql線程都不用重啟喲);而類似sql_slave_skip_counter=N和slave-skip-errors?=?N?這樣的粗暴跳過錯誤方法可能破壞主備一致性。但官方文檔的描述很簡潔,我一直好奇slave_exec_mode=IDEMPOTENT?是如何在復(fù)制出錯時保持一致性的--譬如主鍵沖突時是簡單跳過還是覆寫,今天在Percona?5.7下做了個實驗(binlog是row格式),實驗過程就省略了,直接總結(jié)如下: 1.insert場景 此時insert?into語句在備機(jī)的效果就跟replace?into一樣,但卻并不是把insert?into轉(zhuǎn)換成replace?into來執(zhí)行,分兩種情況: a.MySQL配置成autocommit,直接一條insert?into?... 如這樣的insert insert?into?test?set?c1='a',c2='b'; 此時insert?into語句在備機(jī)執(zhí)行時假如遇到主鍵沖突就先轉(zhuǎn)化為delete再insert delete?from?test?where?c1='old_value'?and?c2='old_value';??? insert?into?test?set?c1='a',c2='b';??? 假如遇到非主鍵的唯一鍵沖突就轉(zhuǎn)換為update update?test?set?set?c1='a',c2='b'?where?c1='old_value'?and?c2='old_value'; b.當(dāng)顯示開始事務(wù)時(begin...insert?into...commit;) 如這樣的sql begin;??? ......? insert?into?test?set?c1='a',c2='b';??? ......? commit;??? 此時begin...commit里的insert?into語句在備機(jī)執(zhí)行時假如遇到主鍵沖突、唯一鍵沖突都是先轉(zhuǎn)化為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場景 當(dāng)備機(jī)不存在要更新的記錄,這條update跳過不執(zhí)行 3.delete場景? 同update場景一樣,備機(jī)跳過此delete啥也不干 注意:使用冥等模式時表要有主鍵 冥等模式并不是萬能的,除了不能對DDL操作冥等,對字段長度不同導(dǎo)致的錯誤也不是冥等(譬如主機(jī)一個字段是char(20)而備機(jī)是char(10)),還有一個限制就是表有主鍵才會對insert的冥等設(shè)置有效:因為insert的冥等行為是通過主鍵來判斷備機(jī)是否有重復(fù)值從而產(chǎn)生覆寫操作,如果表沒有主鍵,則備機(jī)即使設(shè)了冥等也可能會比主機(jī)多重復(fù)數(shù)據(jù)。
About Me
| ........................................................................................................................ ● 本文作者:小麥苗,部分內(nèi)容整理自網(wǎng)絡(luò),若有侵權(quán)請聯(lián)系小麥苗刪除 ● 本文在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/ ● 數(shù)據(jù)庫筆試面試題庫及解答: http://blog.itpub.net/26736162/viewspace-2134706/ ● DBA寶典今日頭條號地址: http://www.toutiao.com/c/user/6401772890/#mid=1564638659405826 ........................................................................................................................ ● QQ群號: 230161599 (滿) 、618766405 ● 微 信群:可加我微 信,我拉大家進(jìn)群,非誠勿擾 ● 聯(lián)系我請加QQ好友 ( 646634621 ) ,注明添加緣由 ● 于 2019-07-01 06:00 ~ 2019-07-31 24:00 在西安完成 ● 最新修改時間:2019-07-01 06:00 ~ 2019-07-31 24:00 ● 文章內(nèi)容來源于小麥苗的學(xué)習(xí)筆記,部分整理自網(wǎng)絡(luò),若有侵權(quán)或不當(dāng)之處還請諒解 ● 版權(quán)所有,歡迎分享本文,轉(zhuǎn)載請保留出處 ........................................................................................................................ ● 小麥苗的微店 : https://weidian.com/s/793741433?wfr=c&ifr=shopdetail ● 小麥苗出版的數(shù)據(jù)庫類叢書 : http://blog.itpub.net/26736162/viewspace-2142121/ ● 小麥苗OCP、OCM、高可用網(wǎng)絡(luò)班 : http://blog.itpub.net/26736162/viewspace-2148098/ ● 小麥苗騰訊課堂主頁 : https://lhr.ke.qq.com/ ........................................................................................................................ 使用 微 信客戶端 掃描下面的二維碼來關(guān)注小麥苗的微 信公眾號( xiaomaimiaolhr )及QQ群(DBA寶典)、添加小麥苗微 信, 學(xué)習(xí)最實用的數(shù)據(jù)庫技術(shù)。
........................................................................................................................ |
?
?
來自 “ ITPUB博客 ” ,鏈接:http://blog.itpub.net/26736162/viewspace-2651331/,如需轉(zhuǎn)載,請注明出處,否則將追究法律責(zé)任。
總結(jié)
以上是生活随笔為你收集整理的MySQL复制跳过错误--slave_skip_errors、sql_slave_skip_counter、slave_exec_mode的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HDU 3613 Best Reward
- 下一篇: LeetCode-数据库题(二) (52