基于Redo log & Undo log的MySQL的崩潰恢復
Redo log Undo log
Redo log 重做日志,記錄,修改過的數據
Undo log 回滾日志,記錄修改之前的數據
兩個我不做詳細的介紹了,redo log就是記錄哪些地方被修改了
undo log是記錄修改之前我們的數據長什么樣
更新流程
我們來捋一下這個流程,首先是更新數據,會先去Buffer Pool中查找是否有這個頁,如果說不存在這個頁,就會從磁盤中加載,也就是第二步
第三步,有了這個頁,我們需要先寫Undo log,在一切開始之前,先記錄沒動過的樣子
第四步,就是更新數據,先是寫入Redo log Buffer中,因為一個事務中不止一個修改的地方,所以先寫道Redo log Buffer中,一并寫入到Redo log 文件中去
然后是寫Binlog文件
其中有幾點我們需要繼續探討
為什么要寫入Redo log buffer中?我們修改完頁,為什么不直接刷入到磁盤中去
這個問題很好理解,為什么修改之后,不直接刷入到磁盤去呢?因為這樣子做,效率太低了,我們要刷入到磁盤的化,肯定是以頁為單位的,一個頁是16kb,而且還是隨機IO,那樣寫的太慢了,我么redo log 文件,是順序IO,性能快,而且不是完整的頁
占用內存小,又快,肯定寫到buffer中去,然后寫到redo log file文件中啊
兩階段提交
binlog的一致性問題出現
你可能聽過兩階段提交,就是為了解決binlog的一致性問題的
我們來想想,怎么會出現這個問題
刷盤的目的,無非就是兩個目的,redo log寫到磁盤中去,binlog寫到磁盤中去
那無非就有兩種方案
第一,先寫redo log ,再寫binlog
第二,先寫bin log,再寫redo log
第一種方案:
先寫了redo log,bin log 還沒寫,MySQL宕機,redo log刷入了磁盤,bin log沒有這條記錄,此時bin log就丟失了記錄,出現一致性問題
第二種方案:
先寫bin log,redo log還沒寫,MySQL宕機,此時redo log沒寫,那么重啟的時候,binlog 和redo log又不一樣實際的數據又會丟失
所以我們必須保證一個事情,binlog 和 Redo log 必須保持一致性!!
為了這個目標就有兩階段提交,也就是2PC(two-phase commit protocool)
基于2PC
為了保證事務的一致性,所以就出現了2PC,它將事務的提交分成了兩個不部分Prepare和Commit/Rollback
Prepare階段,首先我們從Redo log Buffer種將Redo Log寫入文件,然后刷入磁盤,記錄上內部的XA事務的ID,同時將Redo log設置為Prepare狀態,Redo log寫入成功,再將Binlog同樣刷入磁盤,記錄XA事務的ID
Commit階段,向磁盤種的Redo log寫入Commit標識,表示事務提交,然后執行器調用存儲引擎的接口提交事務.
驗證
我們來驗證兩階段提交是否可以保證一致性
首先,假設Redo log 刷入成功,但是還沒來得及刷入Binlog,此時宕機,重啟之后發現Redo log 沒有commit標志,那么就會根據記錄的XA事務Id找到這個事務,然后回滾
如果Redo log刷入成功,Binlog也刷入成功,還沒來得及將Redo log從Prepare改成Commit,MySQL宕機,重啟之后,發現雖然Redo log雖然沒有commit標志,但是通過XA事務ID查詢到的Binlog已經刷入到磁盤中去了額,此時MySQL也會提交事務
我比較困惑的時候,如果Redo log刷入盤了,打上了Prepare標志,但是寫Binlog寫到一半的時候,突然MySQL宕機了,此時還會有一致性問題,這里我先放下,之后我懂了再來更新這里的問題