MySQL · 原理介紹 · 再議MySQL的故障恢復

原文:http://mysql.taobao.org/monthly/2018/12/04/

MySQL的事務處理—兩階段事務提交2PC

MySQL數據庫的INNODB是一款支持OLTP的存儲引擎,爲支持MySQL的高可用,支持跨機搭建高可用數據庫集羣,MySQL採用了一種簡單有效的機制-基於binlog的複製,binlog是binary log的簡稱,實際上它是一種邏輯日誌,相對InnoDB引擎的物理日誌,它的數據量更小,格式也更簡單,更易於跨機複製,尤其是對於網絡環境不是很好的情況下,更具有天然的優勢。 那麼MySQL是如何協調InnoDB引擎與Binlog日誌之間的關係呢?MySQL採用了兩階段事務提交(Two-Phase Commit Protocol)協議,當操作完成後,首先Prepare事務,在binlog中實際上只是fake一下,不作任何事情,而是innodb層需要將prepare寫入redolog中;然後執行commit事務,首先在binlog文件中寫入這些操作的binlog日誌,完成後再在Innodb的redolog中寫入commit日誌。

pic

注意在寫binlog日誌時,有個參數sync_binlog來控制何時將binlog fsync到磁盤。

  • 參數爲0時,並不是立即fsync文件到磁盤,而是依賴於操作系統的fsync機制;
  • 參數爲1時,立即fsync文件到磁盤;
  • 參數大於1時,則達到指定提交次數後,統一fsync到磁盤。 因此只有當sync_binlog參數爲1時,纔是最安全的,當其不爲1時,都存在binlog未fsync到磁盤的風險,若此時發生斷電等故障,就有可能出現此事務並未刷出到磁盤,從而故障恢復時將此事務回滾的情況。

基於binlog的事務恢復流程

瞭解了MySQL關於Innodb與Binlog的兩階段提交機制後,就可以更深入去探究MySQL在故障恢復時的處理過程。 在MySQL啓動時,首先會初始化存儲引擎,如本例中的InnoDB引擎,然後InnoDB引擎層會讀取redolog進行InnoDB層的故障恢復,回滾未prepared和commit的事務,但對於已經prepared,但未commit的事務,暫時掛起,保存到一個鏈表中,等待後續讀取binlog日誌,然後根據binlog日誌再對這部分prepared的事務進行處理。 接下來,MySQL會讀取最後一個binlog文件。binlog文件通常是以固定的文件名加一組連續的編號來命名的,並且將其記錄到一個binlog索引文件中,因此索引文件中的最後一個binlog文件即是MySQL將要讀取的最後一個binlog文件。 讀取這個binlog文件時,通過文件頭上是否存在標記LOG_EVENT_BINLOG_IN_USE_F,通過這個標記可以知道上次MySQL是正常關閉還是異常關閉,如果是異常關閉,則會進入故障恢復過程。 進入故障恢復過程後,會依次讀取最後一個binlog文件中的所有log event,並將所有已提交事務的binlog日誌中記錄的xid提取出來添加到hash表中,以備後續對前述InnoDB故障恢復後遺留的Prepared事務繼續處理。另外此處還要定位最後一個完整事務的位置,防止在上次系統異常關閉時有部分binlog日誌未刷到磁盤上,即存在寫了一半的binlog事務日誌,這部分寫了一半binlog日誌的事務在MySQL中會按事務未提交來處理,後續會將其在存儲引擎層回滾。當此文件中的內容全部讀出之後,一是得到一個已提交事務的列表,另一個是最後一個完整事務的位置。 然後檢查由InnoDB層得到的Prepared事務列表,若Prepared事務在從Binlog中得到的提交事務列表中,則在InnoDB層提交此事務,否則回滾此事務。 pic 最後MySQL將最後一個完整事務位置之後的binlog清除,完成故障恢復全部過程。

基於binlog的兩階段提交對高可用複製解決方案的影響

MySQL最常見的高可用解決方案就是基於binlog複製來完成的,通過將master的binlog複製到slave上,然後在slave上重放,從而達到master與slave上數據一致的效果。 正常情況下,這個方案簡單、易用,基本滿足大部分用戶的高可用需求,但在一些特殊情況下,這個方案還是存在一些不足,可能會導致master與slave存在數據不一致的情況。 如果master與slave之間採用異步模式進行binlog複製,顯然就會存在部分binlog未複製到slave的情況。爲提高可用性,MySQL支持semi-sync模式,也就是當master在提交事務之前,保證binlog已經複製到slave,並且收到slave回覆的ACK後,master再將事務提交。Semi-sync模式的複製機制雖然已經極大提高了可用性,但是在極端情況下還是存在master與slave數據不一致的風險,甚至數據丟失的風險。 考慮一下master出現故障後無法立即恢復的情況,爲保障應用的持續性,需要將slave切換爲master。若在故障發生前,master恰好有事務正準備提交,並且binlog日誌已經刷到磁盤,但在將binlog複製給slave過程中master故障了,備機未收到或只收到部分binlog日誌,若此時slave切換爲master,顯然這些未收到或只收到部分binlog日誌的事務是無法重現的,也就是這部分事務是丟失的。理論上應用層並未得到事務提交的反饋,即使事務不存在也不是什麼問題。問題是若此時用戶查詢這些事務不存在,準備重做這些事務,更糟的事情發生了,新的mater也發生故障了,並且無法立即恢復。萬幸的是原來的master可以恢復工作了,直接作爲master就好了,但問題出現了,用戶已經在重做這些事務了,但這些事務在這個master已經存在了,原因如前述的基於binlog的事務恢復。這就好比之前買東西已經付錢給商家200塊了,結果人家說沒收到,我一查賬戶,也沒少錢,那就再付一次吧,結果杯具了,付了400塊給人家??? pic 如上圖所示:若T2的binlog日誌尚未複製到slave時,master故障,原slave切換爲master,而原master重啓恢復後成爲新的slave,如下圖所示: pic

高可用必殺技–基於RAFT的多副本集羣

基於RAFT協議的多副本架構,每一條數據都會被複制多份,通過多副本來增加系統的可用性,防止單副本失效而導致數據不可用。多副本之間基於RAFT協議來實現數據的一致性,只有數據存在於半數以上副本方可認爲數據有效,而無效的副本數據系統會自動修復,從而確保系統只會提供一個統一的一致性視圖。 pic 阿里雲的MySQL金融版就是基於RAFT的多副本集羣,從根本上徹底解決了多副本集羣故障切換後的數據不一致的問題,從而實現RPO等於0的目標,相比傳統的主備集羣有以下優勢:

  • 消除master故障後由於切換master導致的數據不一致;
  • 提供更高可用性,提供鏈路冗餘,防止兩節點主備集羣中主備鏈路不穩定導致的主機hang;
  • 不低於兩節點主備集羣的性能;
  • 節點故障或網絡故障後自動切換master,響應及時;
  • 管理透明,用戶無需額外管理及學習成本;
</section>
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章