作者:胡呈清
愛可生 DBA 團隊成員,擅長故障分析、效能優化,個人部落格:https://www.jianshu.com/u/a95...,歡迎討論。
本文來源:原創投稿
*愛可生開源社群出品,原創內容未經授權不得隨意使用,轉載請聯絡小編並註明來源。
複製異常
在複製過程中,主庫發生故障或者網路中斷,都會造成 slave io thread 中斷,就有可能出現從庫只複製了半個事務的情況。比如主庫執行的事務如下:
begin;
insert 1;
insert 2;
commit;
從庫接收的 binlog 可能只包含事務的一部分,比如:
- 情況1:只包含 begin;
- 情況2:只包含 begin;insert 1;
- 情況3:只包含 begin;insert 1;insert 2;
從庫的 slave sql thread 回放完這部分 binlog 後,會等待 slave io thread 從主庫讀取剩餘的 binlog,而在此之前 sql 執行緒回放這半個事務,就和我們手工執行半個事務一樣,不會提交也不會回滾。
我們應該如何應對這種異常呢?
- 當 slave io thread 恢復,應該做什麼?
- 當 slave io thread 無法恢復,應該做什麼?
實驗過程
測試方法:
##1. 在從庫上用 tc 模擬網路延遲,意在使讀取 binlog 的速度變慢
tc qdisc add dev eth0 root netem delay 3000ms 3000ms 100%
##2. 在主庫執行一個多語句事務
begin;
update t2 set pad='4' where id < 40;
update t2 set pad='5' where id < 50;
update t2 set pad='6' where id < 60;
commit;
##3. 在主庫執行 commit 成功後,立刻用 iptables 切斷主從之間的網路
iptables -A OUTPUT -d 172.16.21.4 -j DROP
iptables -A INPUT -s 172.16.21.4 -j DROP
這樣我們可以在從庫上觀察到的現象為:
- 其中一個 worker 執行緒狀態是
Waiting for an event from Coordinator
,這個狀態說明 work 執行緒已經幹完活在等 Coordinator (協調執行緒)分配新的 relay log event ,但同時又顯示它正在執行update t2 set pad='5' where id < 50
,這是矛盾1:
show slave status
輸出中,Retrieved_Gtid_Set
與Executed_Gtid_Set
相等(意味著sql執行緒已經回放完所有的relay log),但是上圖 worker 執行緒又正在回放SQL ,這是矛盾2:
最後我們通過 relay log 實錘,可以看到這個事務的 relay log 並不完整,到update t2 set pad='5' where id < 50
; 這個Rows_query event
就結束了:
當 slave io thread 無法恢復
如果 slave io thread 長時間不能恢復,那麼 sql 執行緒會因為等不到剩餘的 binlog,一直無法提交或回滾,會一直持有這個事務的鎖:
如果是主庫故障導致的 slave io thread 異常,那很可能會進行主從切換,這個從庫提升為主後,SQL執行緒持有的事務鎖可能會阻塞業務請求。
此時應該 stop slave 停止 sql 執行緒,讓事務回滾釋放鎖。需要注意的是:此情況下 stop slave 會等待 60 秒(等 slave io thread 接收事務剩餘的binlog),60秒超時後才會停止 sql 執行緒:
當 slave io thread 恢復
slave io thread 異常中斷後,sql 執行緒是正常工作的,sql 執行緒執行了部分事務,並且會等待 io 執行緒傳送新的 binlog。slave io thread 執行緒恢復後,如果是基於 GTID 的複製,會從當前 GTID 事務開始重新獲取完整的 binlog,從庫會先回滾當前事務,然後再重新回放新收到的 binlog 。