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