MySQL 原理研究:mysql(innodb存儲引擎)事務日誌


一、緣由:我的mysql中有兩個文件(ib_logfile0、ib_logfile1),對於它們的作用等等,不甚瞭解。


二、內容:

ib_logfile0、ib_logfile1是mysql中innodb下的的事務日誌,因爲myisam不支持事務,所以也就沒有事務日誌了。可以通過innodb_log_file_size=50M參數設置大小。


事務日誌的作用:

主要是用來保證innodb事務的安全性,通過在線redo日誌和記錄在表空間的undo信息來保證事務安全性,redo日誌記錄了innodb所有做的物理變更和事務信息。個人認爲事務日誌應該包括redo log和undo log,而redo日誌則記錄在上面的兩個文件中。上面已經說了undo log記錄在表空間裏面。事務日誌裏面記錄的是關於每個頁的更改的物理情況。


LSN:日誌序列號,innodb的日誌序列號是一個64位的整數。


1.checkpoint寫入:

innodb實現了fuzzy checkpoint的機制,每次取到最老的髒頁,然後確保此髒頁對應的LSN之前的LSN都已經寫入了日誌文件,再將此髒頁的LSN作爲checkpoint點記錄到日誌文件,意思就是"這個LSN之前的LSN對應的日誌和數據都已經寫入了磁盤文件"。恢復數據文件的時候,innodb掃描日誌文件,當發現LSN小於checkpoint對應的LSN,就認爲恢復已經完成。

checkpoint寫入的位置在日誌文件開頭固定的偏移量處,即每次寫checkpoint都覆蓋之前的checkpoint信息。



2.管理機制:

日誌生命週期和對應的日誌信息:

創建事務日誌-------------------------------------log sequence number(LSN1)

日誌刷盤-----------------------------------------log flushed up to(LSN2)

數據刷盤-----------------------------------------oldest modified data log(LSN3)

寫checkpoint-------------------------------------last checkpoint at(LSN4)


創建日誌:事務創建一條日誌。

日誌刷新:日誌寫入到磁盤上的日誌文件。

數據刷頻:日誌對應的髒數據寫入到磁盤上的數據文件。

寫checkpoint:日誌被當做checkpoint寫入日誌文件。


對應的4個階段,系統記錄了上面的4個日誌相關信息:

log sequence number(LSN1):表明事務日誌產生到了什麼位置。

log flushed up to(LSN2:表明寫到事務日誌的磁盤文件的位置。

oldest modified data log(LSN3):表明髒數據寫入到數據文件的位置。

last checkpoint at(LSN4):表明事務日誌文件和數據的磁盤文件都完成的位置。


對於mysql系統來說它們的關係爲LSN1>=LSN2>=LSN3>=LSN4

我們可以看到我們自己的mysql中的log信息:

------------------------------------------------------------------------------------------------------

mysql> show engine innodb status\G

---

LOG

---

Log sequence number 1817745

Log flushed up to   1817745

Last checkpoint at  1817745

0 pending log writes, 0 pending chkp writes

285 log i/o's done, 0.00 log i/o's/second

-------------------------------------------------------------------------------------------------------



3.保護機制:

innodb的數據並不是實時寫盤的,爲了避免宕機時數據丟失,保證數據的ACID屬性,innodb至少要保證數據對應的日誌不能丟失,對於不同的情況。innodb採用不同的策略:


宕機導致日誌丟失:

innodb有日誌刷盤機制,可以通過innodb_flush_log_at_trx_commit參數進行控制。


日誌覆蓋導致日誌丟失:

innodb日誌文件大小是固定的,寫入的時候通過取餘來計算偏移量,這樣存在兩個LSN寫入到同一位置的可能,後面寫的把前面寫的就覆蓋掉了,例如:LSN=100000000和LSN=1600000000兩個日誌的偏移量是相同的。這種情況下,爲了保證數據一致性,必須要求LSN=100000000對應的髒頁數據都已經刷新到磁盤中,也就是要求last checkpoint對應的LSN一定要大於100000000,否則覆蓋後日志也沒有了,數據也沒有刷盤,一旦宕機,數據就丟失了。


爲了解決第二種情況導致數據丟失的問題,innodb實現了一套日誌保護機制,如下所示:


O----ckp age----buf age----buf async----buf sync----ckp async----ckp sync----O

在上面,整條線代表了日誌空間(log cap,約等於日誌文件總大小*0.8,0.8是一個安全係數),ckp age和buf age是兩個浮動的點,buf async、buf sync、ckp async、ckp sync是幾個固定的點。概念如下:


ckp age  LSN1-LSN4  還沒有做Checkpoint的日誌範圍,若Ckp age超過日誌空間,說明被覆蓋的日誌(LSN1-LSN4-Log cap)對應日誌和數據“可能”還沒有刷到磁盤上。


buf age LSN1-LSN3   還沒有將髒頁刷盤的日誌的範圍,若Buf age超過日誌空間,說明被覆蓋的日誌(LSN1-LSN3-Log cap)對應數據“肯定”還沒有刷到磁盤上。


buf async 日誌空間大小*7/8   

強制將Buf age-Buf async的髒頁刷盤,此時事務還可以繼續執行,所以爲async,對事務的執行速度沒有直接影響(有間接影響,例如CPU和磁盤更忙了,事務的執行速度可能受到影響)。


buf sync 日誌空間大小*15/16   強制將2*(Buf age-Buf async)的髒頁刷盤,此時事務停止執行,所以爲sync,由於有大量的髒頁刷盤,因此阻塞的時間比Ckp sync要長。


ckp async 日誌空間大小*31/32   強制寫Checkpoint,此時事務還可以繼續執行,所以爲async,對事務的執行速度沒有影響(間接影響也不大,因爲寫Checkpoint的操作比較簡單)。


ckp sync 日誌空間大小*64/64   強制寫Checkpoint,此時事務停止執行,所以爲sync,但由於寫Checkpoint的操作比較簡單,即使阻塞,時間也很短。



當事務執行速度大於髒頁刷盤速度時,Ckp age和Buf age會逐步增長,當達到async點的時候,強制進行髒頁刷盤或者寫Checkpoint,如果這樣做還是趕不上事務執行的速度,則爲了避免數據丟失,到達sync點的時候,會阻塞其它所有的事務,專門進行髒頁刷盤或者寫Checkpoint。

因此從理論上來說,只要事務執行速度大於髒頁刷盤速度,最終都會觸發日誌保護機制,進而將事務阻塞,導致MySQL操作掛起。


由於寫Checkpoint本身的操作相比寫髒頁要簡單,耗費時間也要少得多,且Ckp sync點在Buf sync點之後,因此絕大部分的阻塞都是阻塞在了Buf sync點,這也是當事務阻塞的時候,IO很高的原因,因爲這個時候在不斷的刷髒頁數據到磁盤。



4.數據恢復:


4.1系統故障造成數據庫不一致的原因有兩個:

4.1.1.未完成事務對數據庫的更新,可能已寫入數據庫。

4.1.2.已提交事務對數據庫的更新,可能還留在緩衝區沒有來得及寫入數據庫。



4.2.恢復的方法:

4.2.1正向掃描日誌文件(從頭到尾),找出故障發生前已經提交的事務(存在begin transaction和commit記錄),將其標示記入重做(redo)隊列。同事找出故障發生時未完成的事務(只有begin transaction,沒有commit),將其標識記入(undo)隊列。


4.2.2對undo隊列的各事務進行撤銷處理。進行undo的處理方法是,反向掃描日誌文件,對每個undo事務的更新操作執行反操作,即將日誌記錄中"更新前的值"寫入數據庫。


4.2.3對重做日誌中的各事務進行重做操作。進行redo的處理方法是,正向掃描日誌文件,對每個redo事務重新執行日誌文件登記操作。即將日誌中"更新後的值"寫入數據庫。


文章轉載自:http://hi.baidu.com/green_lizard/item/051005d2736f910de1f46fc6

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章