目錄
- MySQL崩潰恢復(fù)流程
- 1、黑盒下的更新數(shù)據(jù)流程
- 2、Redo Log Undo Log
- 3、實現(xiàn)日志后的更新流程
- 3、流程中仍然存在的問題
- 4、基于2PC的一致性保障
- 5、驗證2PC機制的可用性
MySQL崩潰恢復(fù)流程
Buffer Pool是MySQL內(nèi)存結(jié)構(gòu)中十分核心的一個組成,你可以先把它想象成一個黑盒子。
1、黑盒下的更新數(shù)據(jù)流程
當(dāng)我們查詢數(shù)據(jù)的時候,會先去Buffer Pool中查詢。如果Buffer Pool中不存在,存儲引擎會先將數(shù)據(jù)從磁盤加載到Buffer Pool中,然后將數(shù)據(jù)返回給客戶端;同理,當(dāng)我們更新某個數(shù)據(jù)的時候,如果這個數(shù)據(jù)不存在于Buffer Pool,同樣會先數(shù)據(jù)加載進(jìn)來,然后修改修改內(nèi)存的數(shù)據(jù)。被修改過的數(shù)據(jù)會在之后統(tǒng)一刷入磁盤。
MySQL 奔潰恢復(fù):
這個過程看似沒啥問題,實則不講武德。假設(shè)我們修改Buffer Pool中的數(shù)據(jù)成功,但是還沒來得及將數(shù)據(jù)刷入磁盤MySQL就掛了怎么辦?按照上圖的邏輯,此時更新之后的數(shù)據(jù)只存在于Buffer Pool中,如果此時MySQL宕機了,這部分?jǐn)?shù)據(jù)將會永久的丟失;
再者,我更新到一半突然發(fā)生錯誤了,想要回滾到更新之前的版本,該怎么辦?那不完犢子嗎,連數(shù)據(jù)持久化的保證、事務(wù)回滾都做不到還談什么崩潰恢復(fù)?
2、Redo Log Undo Log
而通過MySQL能夠?qū)崿F(xiàn)崩潰恢復(fù)的事實來看,MySQL必定實現(xiàn)了某些騷操作。沒錯,這就是接下來我們要介紹的另外的兩個關(guān)鍵功能,Redo Log和Undo Log。
這兩種日志是屬于InnoDB存儲引擎的日志,和MySQL Server的Binlog不是一個維度的日志。
(1)Redo Log 記錄了此次事務(wù)「完成后」的數(shù)據(jù)狀態(tài),記錄的是更新之「后」的值
(2)Undo Log 記錄了此次事務(wù)「開始前」的數(shù)據(jù)狀態(tài),記錄的是更新之「前」的值
所以這兩種日志有明顯的區(qū)別,我用一種更加通俗的例子來解釋一下這兩種日志。
Redo Log就像你在命令行敲了很長的命令,敲回車執(zhí)行,結(jié)果報錯了。此時我們只需要再敲個↑就會拿到上一條命令,再執(zhí)行一遍即可。
Undo Log就像你剛剛在Git中Commit了一下,然后再做一個較為復(fù)雜的改動,但是改著改著你的心態(tài)崩了,不想要剛剛的改動了,于是直接git reset --hard $lastCommitId
回到了上一個版本。
3、實現(xiàn)日志后的更新流程
有了Redo Log和Undo Log,我們再將上面的那張圖給完善一下。
MySQL 崩潰恢復(fù):
首先,更新數(shù)據(jù)還是會判斷數(shù)據(jù)是否存在于Buffer Pool中,不存在則加載。上面我們提到了回滾的問題,在更新Buffer Pool中的數(shù)據(jù)之前,我們需要先將該數(shù)據(jù)事務(wù)開始之前的狀態(tài)寫入Undo Log中。假設(shè)更新到一半出錯了,我們就可以通過Undo Log來回滾到事務(wù)開始前。
然后執(zhí)行器會更新Buffer Pool中的數(shù)據(jù),成功更新后會將數(shù)據(jù)最新狀態(tài)寫入Redo Log Buffer中。因為一個事務(wù)中可能涉及到多次讀寫操作,寫入Buffer中分組寫入,比起一條條的寫入磁盤文件,效率會高很多。
redo-log-buffer:
那為什么Undo Log不也搞一個Undo Log Buffer,也給Undo Log提提速,雨露均沾?那我們假設(shè)有這個一個Buffer存在于InnoDB,將事務(wù)開始前的數(shù)據(jù)狀態(tài)寫入了Undo Log Buffer中,然后開始更新數(shù)據(jù)。
突然啪一下,很快啊,MySQL由于意外進(jìn)程退出了,此時會發(fā)生一件很尷尬的事情,如果更新的數(shù)據(jù)一部分已經(jīng)刷回磁盤了,但是此時事務(wù)沒有成功需要回滾,你發(fā)現(xiàn)Undo Log隨著進(jìn)程退出一起沒了,此時就沒有辦法通過Undo Log去做回滾。
那如果剛剛更新完內(nèi)存,MySQL就掛了呢?此時Redo Log Buffer甚至都可能沒有寫入,即使寫入了也沒有刷到磁盤,Redo Log也丟了。
其實無所謂,因為意外宕機,該事務(wù)沒有成功,既然事務(wù)事務(wù)沒有成功那就需要回滾,而MySQL重啟后會讀取磁盤上的Redo Log文件,將其狀態(tài)給加載到Buffer Pool中。而通過磁盤Redo Log文件恢復(fù)的狀態(tài)和宕機前事務(wù)開始前的狀態(tài)是一樣的,所以是沒有影響的。然后等待事務(wù)commit了之后就會將Redo Log和Binlog刷到磁盤。
3、流程中仍然存在的問題
你可能認(rèn)為到這一步就完美了,事實上則不然。假設(shè)我們在將Redo Log刷入到磁盤之后MySQL突然宕機了,binlog還沒有來得及寫入。此時重啟,Redo Log所代表的狀態(tài)就和Binlog所代表的狀態(tài)不一致了。Redo Log恢復(fù)到Buffer Pool中的某行的A字段是3,但是任何監(jiān)聽其Binlog的數(shù)據(jù)庫讀取出來的數(shù)據(jù)確是2。
即使Redo Log和Binlog都寫入文件了,但是這個時候MySQL所在的物理機活著VM宕機了,日志仍然會丟失?,F(xiàn)在的OS在你寫入文件的時候,會先將改動的內(nèi)容寫入的OS Cache中,以此來提高效率。然后根據(jù)策略(受你配置的參數(shù)的影響)來將OS Cache中的數(shù)據(jù)刷入磁盤。
4、基于2PC的一致性保障
從這你可以發(fā)現(xiàn)一個關(guān)鍵的問題,那就是必須保證Redo Log和Binlog在事務(wù)提交時的數(shù)據(jù)一致性,要么都存在,要么都不存在。MySQL是通過 **2PC(two-phase commit protocol)**來實現(xiàn)的。
MySQL 崩潰恢復(fù):
簡單介紹一下2PC,它是一種保證分布式事務(wù)數(shù)據(jù)一致性的協(xié)議,它中文名叫兩階段提交,它將分布式事務(wù)的提交拆分成了2個階段,分別是Prepare和Commit/Rollback。
就向兩個拳擊手開始比賽之前,裁判會在中間確認(rèn)兩個選手的狀態(tài),類似于問你準(zhǔn)備好了嗎?得到確認(rèn)之后,裁判才會說Fight。
裁判詢問選手的狀態(tài),對應(yīng)的是第一階段Prepare
;得到了肯定的回答之后,裁判宣布比賽正式開始,對應(yīng)的是第二階段Commit
,但是如果有一方選手沒有準(zhǔn)備好,裁判會宣布比賽暫停,此時對應(yīng)的是第一階段失敗的情況,第二階段的狀態(tài)會變?yōu)?strong>Rollback。裁判就對應(yīng)2PC中的協(xié)調(diào)者Coordinator
,選手就對應(yīng)參與者Participant
。
下面我們通過一張圖來看一下整個流程:2PC刷入磁盤
Prepare階段,將Redo Log寫入文件,并刷入磁盤,記錄上內(nèi)部XA事務(wù)的ID,同時將Redo Log狀態(tài)設(shè)置為Prepare。Redo Log寫入成功后,再將Binlog同樣刷入磁盤,記錄XA事務(wù)ID。
Commit階段,向磁盤中的Redo Log寫入Commit標(biāo)識,表示事務(wù)提交。然后執(zhí)行器調(diào)用存儲引擎的接口提交事務(wù)。這就是整個過程。
5、驗證2PC機制的可用性
這就是2PC提交Redo Log和Binlog的過程,那在這個期間發(fā)生了異常,2PC這套機制真的能保證數(shù)據(jù)一致性嗎?
假設(shè)Redo Log刷入成功了,但是還沒來得及刷入Binlog MySQL就掛了。此時重啟之后會發(fā)現(xiàn)Redo Log并沒有Commit標(biāo)識,此時根據(jù)記錄的XA事務(wù)找到這個事務(wù),進(jìn)行回滾。
如果Redo Log刷入成功,而且Binlog也刷入成功了,但是還沒有來的及將Redo Log從Prepare改成Commit MySQL就掛了,此時重啟會發(fā)現(xiàn)雖然Redo Log沒有Commit標(biāo)識,但是通過XID查詢到的Binlog卻已經(jīng)成功刷入磁盤了。
此時,雖然Redo Log沒有Commit標(biāo)識,MySQL也要提交這個事務(wù)。因為Binlog一旦寫入,就可能會被從庫或者任何消費Binlog的消費者給消費。如果此時MySQL不提交事務(wù),則可能造成數(shù)據(jù)不一致。而且目前Redo Log和Binlog從數(shù)據(jù)層面上,其實已經(jīng)Ready了,只是差個標(biāo)志位。
到此這篇關(guān)于基于Redo Log和Undo Log的MySQL崩潰恢復(fù)解析的文章就介紹到這了,更多相關(guān)MySQL崩潰恢復(fù)流程內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
您可能感興趣的文章:- MySQL系列之redo log、undo log和binlog詳解
- 詳解MySQL 重做日志(redo log)與回滾日志(undo logo)
- MySQL 撤銷日志與重做日志(Undo Log與Redo Log)相關(guān)總結(jié)
- MySQL中的redo log和undo log日志詳解
- Mysql中undo、redo與binlog的區(qū)別淺析