一、緣由:我的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