Innodb日志機制

1.1. Log & Checkpoint
Innodb的事務(wù)日志是指Redo log,簡稱Log,保存在日志文件ib_logfile里面。Innodb還有另外一個日志Undo log,但Undo log是存放在共享表空間里面的(ibdata文件)。

由于Log和Checkpoint緊密相關(guān),因此將這兩部分合在一起分析。
名詞解釋:LSN,日志序列號,Innodb的日志序列號是一個64位的整型。

1.1.1. 寫入機制
1.1.1.1. Log寫入

LSN實際上對應(yīng)日志文件的偏移量,新的LSN=舊的LSN + 寫入的日志大小。舉例如下:
LSN=1G,日志文件大小總共為600M,本次寫入512字節(jié),則實際寫入操作為:
l 求出偏移量:由于LSN數(shù)值遠大于日志文件大小,因此通過取余方式,得到偏移量為400M;
l 寫入日志:找到偏移400M的位置,寫入512字節(jié)日志內(nèi)容,下一個事務(wù)的LSN就是1000000512;

1.1.1.2. Checkpoint寫入

Innodb實現(xiàn)了Fuzzy Checkpoint的機制,每次取到最老的臟頁,然后確保此臟頁對應(yīng)的LSN之前的LSN都已經(jīng)寫入日志文件,再將此臟頁的LSN作為Checkpoint點記錄到日志文件,意思就是“此LSN之前的LSN對應(yīng)的日志和數(shù)據(jù)都已經(jīng)寫入磁盤文件”?;謴?fù)數(shù)據(jù)文件的時候,Innodb掃描日志文件,當(dāng)發(fā)現(xiàn)LSN小于Checkpoint對應(yīng)的LSN,就認為恢復(fù)已經(jīng)完成。
Checkpoint寫入的位置在日志文件開頭固定的偏移量處,即每次寫Checkpoint都覆蓋之前的Checkpoint信息。

1.1.2. 管理機制

由于Checkpoint和日志緊密相關(guān),將日志和Checkpoint一起說明,詳細的實現(xiàn)機制如下:

如上圖所示,Innodb的一條事務(wù)日志共經(jīng)歷4個階段:
l 創(chuàng)建階段:事務(wù)創(chuàng)建一條日志;
l 日志刷盤:日志寫入到磁盤上的日志文件;
l 數(shù)據(jù)刷盤:日志對應(yīng)的臟頁數(shù)據(jù)寫入到磁盤上的數(shù)據(jù)文件;
l 寫CKP:日志被當(dāng)作Checkpoint寫入日志文件;

對應(yīng)這4個階段,系統(tǒng)記錄了4個日志相關(guān)的信息,用于其它各種處理使用:
l Log sequence number(LSN1):當(dāng)前系統(tǒng)LSN最大值,新的事務(wù)日志LSN將在此基礎(chǔ)上生成(LSN1+新日志的大?。?;
l Log flushed up to(LSN2):當(dāng)前已經(jīng)寫入日志文件的LSN;
l Oldest modified data log(LSN3):當(dāng)前最舊的臟頁數(shù)據(jù)對應(yīng)的LSN,寫Checkpoint的時候直接將此LSN寫入到日志文件;
l Last checkpoint at(LSN4):當(dāng)前已經(jīng)寫入Checkpoint的LSN;

對于系統(tǒng)來說,以上4個LSN是遞減的,即: LSN1>=LSN2>=LSN3>=LSN4.

具體的樣例如下(使用show innodb status /G命令查看,Oldest modified data log沒有顯示):


1.1.3. 保護機制

Innodb的數(shù)據(jù)并不是實時寫盤的,為了避免宕機時數(shù)據(jù)丟失,保證數(shù)據(jù)的ACID屬性,Innodb至少要保證數(shù)據(jù)對應(yīng)的日志不能丟失。對于不同的情況,Innodb采取不同的對策:
l 宕機導(dǎo)致日志丟失Innodb有日志刷盤機制,可以通過innodb_flush_log_at_trx_commit參數(shù)進行控制;
l 日志覆蓋導(dǎo)致日志丟失
Innodb日志文件大小是固定的,寫入的時候通過取余來計算偏移量,這樣存在兩個LSN寫入到同一位置的可能,后面寫的把前面寫得就覆蓋了,以“寫入機制”章節(jié)的樣例為例,LSN=100000000和LSN=1600000000兩個日志的偏移量是相同的了。這種情況下,為了保證數(shù)據(jù)一致性,必須要求LSN=1000000000對應(yīng)的臟頁數(shù)據(jù)都已經(jīng)刷到磁盤中,也就是要求Last checkpoint對應(yīng)的LSN一定要大于1000000000,否則覆蓋后日志也沒有了,數(shù)據(jù)也沒有刷盤,一旦宕機,數(shù)據(jù)就丟失了。

為了解決第二種情況導(dǎo)致數(shù)據(jù)丟失的問題,Innodb實現(xiàn)了一套日志保護機制,詳細實現(xiàn)如下:


上圖中,直線代表日志空間(Log cap,約等于日志文件總大小*0.8,0.8是一個安全系數(shù)),Ckp age和Buf age是兩個浮動的點,Buf async、Buf sync、Ckp async、Ckp sync是幾個固定的點。各個概念的含義如下:

Paste_Image.png

當(dāng)事務(wù)執(zhí)行速度大于臟頁刷盤速度時,Ckp age和Buf age會逐步增長,當(dāng)達到async點的時候,強制進行臟頁刷盤或者寫Checkpoint,如果這樣做還是趕不上事務(wù)執(zhí)行的速度,則為了避免數(shù)據(jù)丟失,到達sync點的時候,會阻塞其它所有的事務(wù),專門進行臟頁刷盤或者寫Checkpoint。

因此從理論上來說,只要事務(wù)執(zhí)行速度大于臟頁刷盤速度,最終都會觸發(fā)日志保護機制,進而將事務(wù)阻塞,導(dǎo)致MySQL操作掛起。

由于寫Checkpoint本身的操作相比寫臟頁要簡單,耗費時間也要少得多,且Ckp sync點在Buf sync點之后,因此絕大部分的阻塞都是阻塞在了Buf sync點,這也是當(dāng)事務(wù)阻塞的時候,IO很高的原因,因為這個時候在不斷的刷臟頁數(shù)據(jù)到磁盤。例如如下截圖的日志顯示了很多事務(wù)阻塞在了Buf sync點:


附注:Innodb的日志保護機制實現(xiàn)可以參考log0log.c文件的void log_check_margins(v

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容