前言
許多使用者在他們的資料庫環境中使用半同步複製架構以提高資料的完整性。今天我要向大家介紹一下MySQL在5.7版本中針對半同步複製增加的新特性,這個新特性進一步增強了主庫和備庫之間的資料完整性。
在儲存引擎層提交之前等待從庫ACK
正如你所知的,在半同步複製架構中,主庫上的事務提交之前會等待一個從庫返回ACK訊號。為了進一步增加資料的完整性,新的特性將等待從庫返回ACK訊號的時間點提前了(相對於MySQL5.5以及MySQL5.6),新特性中主庫上的事務會在儲存引擎層提交之前一直等待從庫返回ACK訊號。
有了這個新特性之後,半同步複製可以保證:
- 在主庫crash的情況下,所有在主庫上已經提交的事務已經被複制到至少一個從庫上
顯而易見,因為主庫上的事務無法提交,除非從庫返回了ACK訊號(或者超時)。 這對於使用者來說有兩個有利點:
- 強資料完整性,並解決了幻讀的問題
- 簡化主庫Crash Recovery的過程
強資料完整性解決幻讀問題
在MySQL 5.5以及MySQL 5.6開啟半同步複製的場景下,主庫上的事務在儲存引擎層提交之後,需要等待從庫返回ACK訊號。並且在接收到從庫返回ACK訊號或者等待超時才會返回給客戶端一個提交結果。
儲存引擎層的提交,會持久化記錄並且釋放這些記錄上的鎖。所以在儲存引擎層提交之後,其餘的會話可以操作並讀取這些記錄,即使這個會話還在等待從庫返回ACK訊號。這樣在主庫crash,從庫接管主庫的情況下,產生幻讀的現象。
在這個新特性中,不會發生幻讀。User2在第一次SELECT的時候不會獲取3這個值,因為3這條記錄還沒有複製從庫,所以並沒有在儲存引擎層提交。
簡化主庫Crash Recovery的過程
在MySQL 5.7.2之前的版本中,使用者在恢復crash掉的主庫的時候,需要做以下操作:
- 手動清除並沒有被複制到從庫上的binlog事務
- 手動回滾已經提交但是還沒有被複制的事務
因為新的特性保證所有的事務在提交之前都至少複製到一個從庫上了,所以第二步可以不用做了。
如何設定新特性
這個特性的設定很簡單,使用者無需任何設定,因為在MySQL 5.7.2版本之後該特性是預設開啟的。使用者可以設定rpl_semi_sync_master_wait_point
變數控制主庫等待從庫返回ACK訊號的時間點。
這是一個全域性、可動態修改的引數。在5.7.2版本之後,該變數的預設值是AFTER_SYNC
,該值表示,主庫上的事務會在flush binlog之後,在儲存引擎層提交之前的時間點,等待從庫返回ACK訊號。
你也可以將該引數設定為AFTER_COMMIT
值不開啟新特性,保持和之前版本一樣的機制。但是我想不到一個理由讓使用者設定該變數為AFTER_COMMIT
值。開啟新特性並沒有副作用,也不會對資料庫效能產生影響。
Dump執行緒的優化
在開發這個特性的過程中,我們對Dump執行緒做了一些優化。我們重構了Dump執行緒先關的程式碼,但是更重要的是,在Dump執行緒讀取binlog event的時候,Dump執行緒不會再去獲取binlog鎖。這一改進增加了主庫的一個吞吐量並且減小了主從之間的延遲。
最後
總而言之,這個新特性保證了主庫和從庫之間的資料完整性、一致性,並不會帶來任何副作用以及效能印象。我強烈推薦你去嘗試該特性。
A special thanks to Mr. Zhenxing Zhou a community user who contributed a patch implementing a similar idea based on MySQL 5.5. Even though we did not take his patch (the 5.7 codebase changed quite a lot compared to 5.5), his feature request was yet another source of motivation and inspiration.
部落格地址:win-man.github.io/
公眾號:歡迎關注