MySQL InnoDB Update和Crash Recovery流程詳解
1.2.3 什么是Log Sequence Number (LSN)?
一個64位無符號整數(shù),表示Redo Log系統(tǒng)中的時間點,也是事務寫入Redo Log的字節(jié)總量,從日志初始化開始計數(shù)(數(shù)據庫初始化安裝時間點開始且單調遞增)
LSN不僅存在于Redo Log中,在每個數(shù)據頁中都保存著一個LSN,在進行數(shù)據恢復時通過LSN做比較運算可以判斷出每個數(shù)據頁是否需要進行恢復操作
1.2.4 什么是Checkpoint?
一個時間點,由一個LSN值(Checkpoint LSN)表示的整型值,在Checkpoint LSN之前的每個數(shù)據頁(buffer pool中的臟頁)的更改都已經落盤(刷新到數(shù)據文件中),Checkpoint 完成后,在Checkpoint LSN之前的Redo Log就不再需要了。
Checkpoint技術是為了解決:全量Redo Log恢復時間太長、buffer pool中的空閑頁不夠用時將臟頁刷新到磁盤數(shù)據文件、Redo Log空間不夠用時將臟頁刷新到磁盤數(shù)據文件等問題。
Checkpoint方式有兩種:Sharp Checkpoint和Fuzzy Checkpoint(又可根據不同的場景細分)
Sharp Checkpoint:將所有的臟頁刷回磁盤,數(shù)據庫實例關閉時系統(tǒng)參數(shù)innodb_fast_shutdown設置為0,才需要把所有的臟頁都刷回磁盤,刷臟時系統(tǒng)hang住
Fuzzy Checkpoint:持續(xù)的每次只刷新一部分臟頁到磁盤,數(shù)據庫正常運行過程中都是使用這種方式刷臟,在InnoDB內部還可細分為如下幾種:
Master線程每秒/每十秒固定執(zhí)行Checkpoint
LRU list中空閑頁不夠時,觸發(fā)Checkpoint從LRU list刷新臟頁以釋放足夠的空閑頁
Redo Log空間不夠時,觸發(fā)Checkpoint從Flush list刷新臟頁,Checkpoint執(zhí)行完成之后,在這個位置之前的Redo Log不再需要(即,可以循環(huán)覆蓋使用)
臟頁太多達到臟頁比例閥值(系統(tǒng)參數(shù)innodb_max_dirty_pages_pct和innodb_max_dirty_pages_pct_lwm控制臟頁比例閥值),觸發(fā)Checkpoint
1.2.5 什么是Rollback Pointer (ROLL_PTR)?
一個由rollback segment number、page number和page offset組成的指針,指向Undo Log中包含之前版本數(shù)據的具體Undo Log日志記錄。
可用于為任何數(shù)據記錄回退到一個歷史版本記錄、可用于mvcc中重建舊版本記錄、可用于事務回滾。
1.2.6 什么是Transaction ID (TRX_ID)?
表示事務開始點的一個64位無符號整數(shù)
每個事務的事務號增量增加
事務號會寫入聚簇索引的每個記錄中
最大事務號會寫入系統(tǒng)表空間的TRX_SYS頁
1.2.7 什么是Transaction Serialization Number(TRX_NO) ?
一個64位無符號整數(shù),表示事務提交時的最大TRX_ID
TRX_NO在事務提交時會寫入Undo Log Header
TRX_NO可用于purge Undo Log中的舊版本記錄
2. Update流程2.1 事務start(事務首次開啟)
為這個事務分配事務ID(TRX_ID),該事務ID可能被寫入系統(tǒng)表空間的TRX_SYS頁面中的最大的事務ID字段(Transaction ID)
* 如果系統(tǒng)表空間的TRX_SYS頁面中的最大的事務ID字段被更新,則該更新會被記錄到Redo Log中。
根據分配的TRX_ID創(chuàng)建read view。
2.2 記錄修改(每次只修改一行記錄)
分配Undo Log日志空間
拷貝該記錄修改之前的值到Undo Log中
將Undo Log的修改記錄寫入Redo Log中
在buffer pool中修改數(shù)據頁,回滾段指針指向Undo Log中該記錄之前的版本
將該記錄對應的數(shù)據頁變更部分寫入Undo Log中
buffer pool中該記錄修改之后的數(shù)據頁被標記為”臟頁”(需要刷新到磁盤的數(shù)據頁)
2.3 此時其他事務的修改會怎樣?
一旦記錄被修改,即使沒有提交,其他事務也可能會看到被修改后的記錄,這依賴于他們的事務隔離級別而定:
如果是RU隔離級別,則使用索引頁讀取最新版本記錄
如果是RU隔離級別,則查找記錄的最新提交版本
如果是RR隔離級別,則查找與其read view相對應的記錄版本
任何需要使用索引頁來讀取比最新的版本記錄舊的版本記錄時,都必須使用Undo Log來重建之前的版本記錄。
2.4 事務提交(顯式和隱式提交)
事務對應的Undo Log頁被設置為”purge”(意味著當這個Undo Log頁不再被任何其他事務引用時可以將其清除)
將Undo Log的修改記錄寫入Redo Log中
Redo Log Buffer刷新到磁盤(是否刷盤取決于系統(tǒng)變量innodb_flush_log_at_trx_commit的設置)
2.5 后臺線程刷臟(后臺線程連續(xù)不斷地根據不同觸發(fā)機制觸發(fā)刷新)
查找最舊的“臟”頁面(修改時間最早的頁面)并將其添加到flush batch中
確保在flush batch中中最新的LSN號已經寫入到了Redo Log中且已經落盤
如果開啟了雙寫,則先將臟頁刷新到雙寫緩沖區(qū)(并等待同步)
將每個臟頁從buffer pool中寫入最終目的地:表空間文件中的
PS:對于后臺線程刷臟部分,執(zhí)行刷新臟頁時,與該臟頁的事務是否提交無關,只需要確保該頁對應LSN號的Redo Log記錄落盤,而不會去判斷事務的狀態(tài)是否是提交還是未提交狀態(tài),因為,數(shù)據頁結構中并沒有地方單獨記錄事務的狀態(tài)(即,無法判斷事務是否提交),只是在每行數(shù)據中有記錄事務號、回滾段指針(所以一個頁中也可能包含多個事務的修改記錄)。當需要對某個事務進行回滾時,重新從表空間中讀取這個未提交的臟頁,使用undo log中的反向數(shù)據進行反向修改,然后再重新刷臟。
2.6 定期執(zhí)行Checkpoint
確保比Checkpoint 點更舊(比Checkpoint LSN?。┑呐K頁已刷新到表空間文件,如果存在有比Checkpoint LSN大的臟頁,則立即刷新臟頁到數(shù)據文件中。說白了Checkpoint機制主要作用就是用于刷新臟頁。
把Checkpoint LSN寫到Redo Log Header中 (從這個Checkpoint LSN開始,之前的Redo Log記錄不再需要)。
2.7 后臺線程Purge(后臺線程連續(xù)不斷地根據需要定期執(zhí)行Purge,包括Undo Log和歷史鏈表)
查找每個回滾段中不再需要的最舊的Undo Log
實際上是從索引中刪除任何帶有刪除標記的記錄
釋放Undo Log頁
修剪history lists
3. Creash Recovery流程3.1 什么時候會進行Crash Recovery?
實例崩潰之后重啟
使用一個備份還原(如:LVM 快照、xtrabackup備份)后
在“快速”(innodb_fast_shutdown不為0值關閉實例)關閉實例后重新啟動
3.2 檢測實例是不是干凈地關閉的
打開Redo Logs和系統(tǒng)表空間文件(ibdataN)
讀取并從中找到最大的Checkpoint LSN
從最近的Checkpoint 開始往后掃描Redo Log
如果能夠找到Redo Log記錄,說明還有數(shù)據頁的更改沒有刷新到數(shù)據文件上,啟動Crash Recovery,使用Redo Log來恢復數(shù)據的一致性
3.3 使用所有獨立表空間的表名和表空間ID創(chuàng)建一個名稱到ID的映射
打開datadir下的所有.ibd文件
在這些表空間文件的offset 0的頁(FSP_HDR頁)頭讀取其表空間ID(FSP_HDR頁中FSP Header的前四個字節(jié)記錄著表空間ID)
將表空間ID與表名建立映射
非常好我支持^.^
(1) 100%
不好我反對
(0) 0%