技術分享 | MySQL:從庫複製半個事務會怎麼樣?

愛可生雲資料庫發表於2022-07-07

作者:胡呈清

愛可生 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_SetExecuted_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 。

相關文章