MySQL半同步復制的問題


MySQL是一個RDBMS(關系型數據庫管理系統),由瑞典MySQL AB 公司開發,目前屬於 Oracle 旗下產品。由於其體積小、速度快、擁有成本低,尤其是開放源碼這一特點,廣受各大企業歡迎,包括騰訊,阿里,百度,網易,Google,FaceBook等互聯網巨頭企業。

 

隨着互聯網的高速發展,互聯網服務可用性變得越發重要,數據容災也隨之成為各企業的關鍵任務。在數據容災中,數據庫集群如何處理數據一致性也成為了各企業需要解決的問題。特別在一些新興的金融服務中,MySQL也逐漸成為其核心數據庫,如何保證金錢的准確性則尤為重要。MySQL也從一開始的異步復制,到Google開發的半同步復制,到MySQL 5.7更新的lossless半同步復制,一直在優化集群的數據一致性問題。

 

雖然MySQL一直在優化數據的一致性問題,但問題依然存在,使得各大企業紛紛各自設計一套MySQL補丁來保證數據一致。騰訊數平的TDSQL,騰訊微信的PhxSQL,阿里的AliSQL,網易的InnoSQL等設計都是為了保證數據一致性。MySQL5.7發布的lossless半同步,雖然宣稱zero loss,解決了5.6版本中有可能出現的data lost問題,但其數據一致性仍未完全解決。

 

關於MySQL的具體介紹可以參考MySQL官方PPThttp://www.slideshare.net/andrewjamesmorgan/mysql-high-availability-solutions-feb-2015-webinar

 

MySQL半同步復制的問題

圖1 MySql半同步流程

 

圖1描述了MySQL的Binlog半同步過程。Wait ACK是半同步的關鍵步驟,Master把Binlog發給Slave之后,需要等待Slave的ACK。Master直到成功收到ACK之后,才執行Engine Commit把數據持久化到Storage。具體細節可參考:http://my-replication-life.blogspot.com/2013/09/loss-less-semi-synchronous-replication.html

 

MySQL啟動時,Wait ACK過程會被跳過,導致Engine Commit會被直接執行。具體細節請參考:https://jira.mariadb.org/browse/MDEV-162 

 

下面對MySQL的數據在Master和Slave之間是否能保證一致進行簡單分析。討論均基於各機器數據最終是否一致來展開。下面的分析只針對半同步復制,且假設半同步失敗后不會退化成異步復制。

 

場景1:Master正常工作

Master的數據復制到Slave,Slave與Master保持數據一致。

 

場景2:Master Crash且不切換Master

 

場景2.1

Master已經收到ACK,並執行Engine Commit。Slave與Master保持數據一致。

 

場景2.2 

Master處於Wait ACK階段,存在PendingBinlog(未執行Engine Commit的Binlog)。

圖2 Master重啟時執行EngineCommit,並把Binlog重新復制給Slave

 

Master重啟時執行EngineCommit。Slave重新連接Master,Binlog重新開始復制,隨后Slave數據和Master一致。如圖2。

 

因此,在MySql5.7的情況下,場景2.2能保證Master和Slave之間的數據一致性。但是在MySQL5.6及之前的版本,場景2.2是不能保證數據一致性的,具體請參考:http://my-replication-life.blogspot.com/2013/09/loss-less-semi-synchronous-replication.html

 

場景3:Master Crash且切換Master

 

場景3.1

 

舊Master Crash時,已經收到至少一台Slave的ACK並執行Engine Commit。

 

數據已復制到至少一台Slave,該Slave與舊Master的數據保持一致。

 

場景3.2

舊Master處於Wait ACK階段時Crash,新Master被切換到了一台擁有最新Binlog的Slave。

 

場景3.2中,舊Master中的PendingBinlog存在兩種場景。

 

場景3.2.1

舊Master Crash時Binlog發送失敗,未復制給任何Slave。

圖3 機器A重啟Commit Transaction X。機器A/B數據不一致。

 

 

   
圖4 機器B接收到事務X的重試請求(事務X’)且復制到機器A。

機器A/B數據可能不一致。

 

假設機器A為舊Master,執行事務X時,復制失敗並Crash。隨后機器B成為新Master。機器A重啟時執行Engine Commit,事務X被Commit。此時機器A和機器B的數據一致性被破壞。兩台機器上數據可能不一致。如圖3,圖4。

 

數據不一致的原因是機器A在重啟時對PendingBinlog執行Engine Commit。在切換了Master的情況下,只能通過回滾PendingBinlog解決。

 

 

MySQL半同步插件的維護者也提到了類似的想法:http://my-replication-life.blogspot.com/2013/09/loss-less-semi-synchronous-replication.html

 

場景3.2.2

舊Master Crash時Binlog發送成功,但還未執行Engine Commit。

 

圖6 機器A重啟馬上執行Engine Commit,數據一致

 

假設機器A為舊Master,執行事務X時在執行Commit前Crash,但機器B收到事務X。隨后機器B成為新Master。

 

機器A重啟時對PendingBinlog執行Engine Commit,執行成功后機器A的數據是機器B的子集。此時機器A可從機器B中拉取最新的數據。另外一台Slave機器C可以從這兩台機器中任意拉取。

 

從圖6可以看出,機器A在出現故障時,由於TransactionX已經復制給其中一台Slave和重啟時立刻Commit Transaction X,使得該Slave和Master的數據能保證一致。


圖7 兩台機器出現故障,Master切換可能會丟失數據

 

上述討論都是基於擁有最新數據的Slave和Master不能一起出現故障。當這兩台機器一起出現故障時,進行Master切換則會造成數據丟失。如圖7。

 

對於較小的集群(機器數目小於或者等於3),當出現兩台機器一起發生故障時,可認為集群已無法提供服務(半同步復制無法工作)。

 

對於較大的集群(機器數目大於3),當出現兩台機器一起發生故障,且無法得知該兩台機器的數據狀態時,該集群也無法提供服務(無法確認擁有最新數據的Slave是否包含在故障機器中)。因此,對於較大的集群,通常增加半同步復制等待ACK的數目,使得出現上述狀況時,仍能進行Master切換(非故障機器中,存在擁有最新數據的機器)。

 

增加等待ACK的數目,解決了數據丟失的問題,但同時給數據回滾帶來了難題。

 


圖8

 

如圖8。假設MySQL集群有5台機器,半同步復制需要等待2台Slave的ACK。機器A為舊Master,在執行Wait ACK階段,機器B收到Binlog后,機器A和機器B同時Crash或者被隔離,導致Binlog復制失敗。根據場景3.2.1的分析,當機器C成為Master后,機器A和機器B在恢復服務前需要對其進行數據回滾。但對Slave進行數據回滾較為困難。且若回滾失敗,則會出現數據不一致。

 

對於較小的集群,回滾PendingBinlog比較容易實現。但對於較大的集群,回滾PendingBinlog本身就是一個未解決的難題。

 

MySQL的Master切換問題

Master如何切換同時也是MySQL容災中的一個難題。

一個簡單的Master切換步驟:

1.  Pause舊Master

2.  Start新Master

3.  更換MySQLClient的Master指向IP

 

存在以下幾個問題:

1.  當Master被隔離時,如何將其變更為Slave

解決方法:可修改MySQL的代碼,使用zookeeper等外部輔助服務來自動維護Master的狀態,可解決Master被隔離后不能操作的問題。

 

2.  如何定位擁有最新Binlog數據的MySQL

解決方法:可以通過人工,或者使用外部工具來檢測集群每台MySQL的數據。但當出現故障機器無法訪問時,無法定位。

 

3.  如何進行數據回滾

解決方法:可以通過運維進行人工操作。

 

4.  如何同時更換MySQLClient的Master指向IP

同時更換所有MySQLClient的Master指向IP是一件不可能的事情,因為不可能同一時刻操作所有機器。

 

不能同時更換所有MySQLClient的Master指向IP,導致部分Client會向舊Master發送請求,即出現多個Master同時服務。在使用半同步復制的情況下,多台MySQL不能同時知道Master的去向,使得數據可能產生不一致的情況。

 

圖9


圖10

 

假設機器A是舊Master,機器B是新Master,機器C還沒收到Master更換的通知仍然向機器A復制Binlog。User1在Master切換前已經連上機器A並持續寫入數據。User2在Master切換后開始向機器B寫入數據。由於機器A能把數據復制給機器C,機器B能把數據復制給機器A,因此機器A和機器B都能成功寫入。如圖9。

 

由於機器A和機器B同時寫入數據,數據一致性無法保證。如圖10。

 

總結

從上面分析來看,MySQL的半同步復制和Master切換都存在一些不足。數據復制存在回滾難題,Master切換存在多Master難題。只有解決了這兩大難題,才能保證MySQL集群的數據一致性。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM