跳還是不跳?這是個問題,跳還是問題
周一(2014-11-17)有個項目進行變更,而且是重大變更,DB測操作從早上持續到下午17點,QA同事到晚上10點測試後發現,slave上的資料與master上不一致。
忘介紹了,該項目的該模組有讀請求以及delete邏輯在上面,被嚇到沒?
這個問題應該在情理之中但又在意料之外,其實DBA在下午DB變更時便遇到slave卡住:
Could not execute Delete_rows event on table codcpc_1004pc_0x3EC.mail; Can't find record in 'mail', Error_code: 1032; handler error HA_ERR_KEY_NOT_FOUND; the event's master log binlog.010464, end_log_pos 82113, Error_code: 1032141117 7:54:31 [Warning] Slave: Can't find record in 'mail' Error_code: 1032
我當時的做法是直接跳過不存在的表,寫了下面這個指令碼:
mysqlconn="mysql -uADMIN -p4word" #while [ "1" = "1" ]for i in `seq 1 30`do status=`$mysqlconn -e "show slave status\G;" | grep -i "Last_SQL_Error" | grep -i "mail"` if [ -n "$status" ];then $mysqlconn -vvve "stop slave;set global sql_slave_skip_counter=1;start slave;" sleep 1 else $mysqlconn -vvve "show slave status\G" echo "error is OK!" exit 0 fidone
很奇怪的,本以為得寫死迴圈跑,沒想到在調試 3次以內就過了,當時沒有深究,也因為沒時間深究導致後面的熬夜排查問題。
始作俑者是一條SQL:delete from mail where recipientEntityID in (select userid from test.deltb);
今天出現卡住,主要還是因為Delete_rows發現鍵不存在,如果改為statement,這個問題就不會出現。因為那條罪魁禍首的sql,在slave上肯定能執行下去。
可關鍵是我們的binlog_format是MIXED模式,那麼問題來了,在什麼情況下,binlog_format=mixed時,產生的binlog會轉換為row格式?關於這點我查了官方文檔,看得不是很明白,留待之後更新。
而binlog_format是row模式的時候,skip是以事務層級來的。
下午的刪除裡邊,在master上做的delete,實際上binlog會轉換為很多binlog event,而這些event僅僅被幾個begin commit包圍著。
這也就解釋了上面我的問題。
那麼跳還是不跳?sql_slave_skip_counter=N線上上跳確實存在一定風險。
⑴ InnoDB時,N=1是跳過整個事務,而不只是一條SQL語句
⑵ 當RBR模式時,無論是InnoDB 或MyISAM,binlog event都是以begin;row group;commit來組織,當N=1時跳過的還是整個事務內容
更安全的做法是sql_exec_mode=IDEMPOTENT,只跳過有問題的SQL或者row,相對於sql_slave_skip_counter而言,slave_exec_mode的處理範圍更小、更安全,不過其僅僅適合RBR模式 :(