【MySql】sql_slave_skip_counter 引數的用法解析

小亮520cl發表於2015-09-25
 前一篇文章介紹了當mysql的複製出現slave sql 程式終止時的解決辦法,其中之一使用了sql_slave_skip_counter 來使sql 執行緒跳過遇到錯誤的事件記錄!本文淺析一下sql_slave_skip_counter的具體用法和意義!
set global sql_slave_skip_counter = N
This statement skips the next N events from the master. 
(即是跳過N個events,這裡最重要的是理解event的含義!在mysql中,對於sql的 binary log 實際上是由一連串的event組成的一個組,即事務組。)
在備庫上設定 global sql_slave_skip_counter =N 會跳過當前時間來自於master的之後N個事件,這對於恢復由某條SQL語句引起的從庫複製有效. 此語句只在當slave threads是停止時才有效,否則將發生一條錯誤..每忽略一個事件,N 減一,直到N減為0!
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.
For nontransactional tables, an event group corresponds to a single SQL statement.
Note
   A single transaction can contain changes to both transactional and nontransactional tables.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
### comment ###
   Setting this variable isn't like setting other server variables: you can't read the variable back again as @@sql_slave_skip_counter, and it isn't really a "global variable." Rather, it's a variable that only the slave thread reads.
  When you restart the slave threads again with START SLAVE, the slave skips statements and decrements the variable until it reaches 0, at which point it begins executing statements again. You can watch this happening by executing SHOW SLAVE STATUS, where the variable's value appears in the Skip_Counter column. This is the only place you can see its value.
  The effect is that the setting isn't persistent. If you set it to 1, start the slave, and the slave has an error in replication sometime later, the variable won't still be set to 1. It'll be 0. At that point, if you want the slave to skip the statement that caused the error, you'll have to set it to 1 again.
有關"SET GLOBAL sql_slave_skip_counter"的語法可以參考官方文件
測試環境:
rac3 主庫
rac4 備庫
測試之前保證主從無資料延時,保證資料一致!
1 使用含有 stop slave 的命令, 在主庫上建立測試表,並使用shell 插入資料!
mysql> create table tab_skip(id int);
Query OK, 0 rows affected (0.80 sec)
[root@rac3 mysql]#
 for i in {1..100}; 
   do 
    echo $i; 
    echo "insert into tab_skip(id) values($i)" | mysql -h127.0.0.1 test ; 
    sleep 1;
done;
在備庫 使用 set global sql_slave_skip_counter=1;命令做測試
[root@rac4 mysql]# 
for i in {1..10}; 
do 
   echo $i; 
   echo "slave stop;set global sql_slave_skip_counter=1; slave start;show slave status\G" | mysql -h127.0.0.1 -P3306 test ; 
   sleep 2;
done;
分別在主庫和備庫上進行驗證資料的完整性:
主庫上面:
[root@rac3 mysql]# mysql
mysql> use test;                 
Database changed
mysql> select count(1) from tab_1;
+----------+
| count(1) |
+----------+
|      100 |
+----------+
1 row in set (0.00 sec)
備庫上面,少了 10條資料!因為正是執行set global sql_slave_skip_counter=1;使備庫執行sql replay的時候忽略了事件!
[root@rac4 mysql]# mysql
mysql> use test;
Database changed
mysql> select count(1) from tab_1;  
+----------+
| count(1) |
+----------+
|       90 |
+----------+
1 row in set (0.00 sec)

有網友測試的是在備庫上執行沒有stop slave 語句的命令,但是在5.5.18版本上面是不允許的!
[root@rac3 mysql]# for i in {1..100}; do echo $i; echo "insert into tab_2(id) values($i)" | mysql -h127.0.0.1 test ; sleep 2;done;   
1
....
100

在備庫上執行,注:"set global sql_slave_skip_counter=1; slave start;show slave status\G"  沒有stop slave 語句,報錯!
[root@rac4 mysql]# for i in {1..10}; do echo $i; echo "set global sql_slave_skip_counter=1; slave start;show slave status\G" | mysql -h127.0.0.1 -P3306 test ; sleep 2;done;          
1
ERROR 1198 (HY000) at line 1: This operation cannot be performed with a running slave; run STOP SLAVE first
2
ERROR 1198 (HY000) at line 1: This operation cannot be performed with a running slave; run STOP SLAVE first
3
ERROR 1198 (HY000) at line 1: This operation cannot be performed with a running slave; run STOP SLAVE first
4
ERROR 1198 (HY000) at line 1: This operation cannot be performed with a running slave; run STOP SLAVE first

使用 該引數能夠解決從伺服器sql 程式停止導致的資料庫不同步,但是也有一定的風險,比如在高併發的資料庫環境下,可能會導致資料丟失!
另見另一位網友的測試實驗(多少有些出入,他的可以不使用stop slave)



補充比較好的一點概念

  1. 背景知識1:
  2.     在主從庫維護中,有時候需要跳過某個無法執行的命令,需要在slave處於stop狀態下,執行 set global sql_slave_skip_counter=N以跳過命令。常用的且不易用錯的是N=1的情況,但N>1時,則不那麼顧名思義,本文詳細介紹N的意義,及使用注意事項。
  3.  
  4.     背景知識2:
  5.     MySQL從庫從主庫上覆制binlog檔案內容到本地執行。在binlog上命令以event的形式存在,並非一個命令對應一個event。以一個insert語句為例(引擎InnoDB、binglog_format=statement), 在binlog中實際上有三個event,分別為begin\insert\commit 。 命令型別都是Query_log_event.
  6.  
  7.     而set global sql_slave_skip_counter=N的意思,即為在start slave時,從當前位置起,跳過N個event。每跳過一個event,則N--.
  8.  
  9.     與實際情況不符?
  10.     看到這裡有同學就會問,這是有問題的。如果當前的執行位置是某個insert語句開頭,那使用 N=1實際上是從begin\insert\commit的第二個開始執行,這個insert語句還是不能被跳過?
  11.     實際上這裡還有兩個策略:
  12.     1、若N=1且當前event為BEGIN, 則N不變,跳過當前event繼續。
  13.     2、若N=1且當前event處於一個事務之內(BEGIN之後,COMMIT之前),則N不變,跳過當前event繼續。
  14.  
  15.      說明:其實上面兩個策略合起來就是一句話,當N=1時,會連續跳過若干個event,直到當前所在的事務結束。
  16.     當然如果N>1,則每跳過一個event都要N--.
  17.  
  18.     命令舉例:
  19.     所以我們平時最常用的N=1的情況,都是下一個事務。
  20.     假設某個Pos之後執行如下命令( 引擎InnoDB、binglog_format=statement)
  21.     insert into t values(x1);
  22.     begin;
  23.     insert into t values(x2);
  24.     insert into t values(x3);
  25.     commit;
  26.    insert into t values(x4);
  27. 你的從庫stop在Pos上,假設你要跳過前面幾個命令直接執行插入x4的操作,則你的N設定為 4或5或6或7均可。(X1語句為3個event)
  28.  
  29.    其他說明:
  30.    上面舉例中都特別說明了在innodb引擎和statement模式下。其他情況區別如下:
  31.    1、若引擎為myisam(等不支援事務的引擎),且在statement下,則binlog中不會有begin和commit,每個命令都是一個event;
  32.    2、row模式的binlog裡,一個insert語句實際上是兩個event(Table_map_event和 Row_log_event), 計算時應與statement不同。
  33.   3、在row模式下,不論引擎是否支援事務,一個insert語句都會加上BEGIN和commit,也即變成4個event。
  34.   4、基於InnoDB引擎表的insert/delete/update操作都有顯式樣的BEGIN /COMMIT.
  35.  
  36.   上面舉的這個例子中,若為row模式,則要直接執行X4語句需要設定的N為 5~10均可。
  37.  
  38.    小結:
  39.    1、set global sql_slave_skip_counter=N中的N是指跳過N個event
  40.    2、最好記的是N被設定為1時,效果跳過下一個事務。
  41.    3、跳過第N個event後,位置若剛好落在一個事務內部,則會跳過這整個事務
  42.    4、一個insert/update/delete不一定只對應一個event,由引擎和日誌格式決定


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

相關文章