詳解 MySQL 重做日志 redolog
redo log也就是所謂的重做日志,是innoDb存儲引擎獨有的日志,它使得MySQL在宕機情況下依舊可以redo log完成數(shù)據(jù)具備恢復能力, 從而保證數(shù)據(jù)完整性,本文將針對該日志進行分析講解,希望對你有幫助。

redolog的作用
redo log是InnoDB存儲引擎獨有的日志,用于MySQL工作過程中崩潰或者宕機時進行數(shù)據(jù)恢復的文件,從而保證數(shù)據(jù)的持久性以及完整性。

redolog是如何運行工作的
我們都知道數(shù)據(jù)庫數(shù)據(jù)基本單位也是和操作系統(tǒng)一致的,都是以頁為單位,我們以MySQL數(shù)據(jù)查詢?yōu)槔瑸榱吮M可能減少IO次數(shù),MySQL在進行數(shù)據(jù)查詢會優(yōu)先將數(shù)據(jù)查詢并存儲到buffer Pool中,在事務提交后將修改操作按照配置的刷盤機制寫回磁盤中。
例如當我們需要對數(shù)據(jù)修改(update)操作時,基于buffer pool完成高效的數(shù)據(jù)更新操作后將事務提交,此時我們的redo日志數(shù)據(jù)就會按照innodb_flush_log_at_trx_commit指定的刷盤機制叫redolog緩存數(shù)據(jù)刷盤:

默認情況下redo日志對應的緩沖區(qū)大小為16M,該變量我們可以通過如下語句查看:
SHOW VARIABLES LIKE 'innodb_log_buffer_size';對應查詢結果如下:
Variable_name |Value |
----------------------+--------+
innodb_log_buffer_size|16777216|redolog幾個刷盤時機
上文圖解的第四步提到了redo log刷盤的操作,當符合以下幾種條件時,對應redo log buffer會被刷盤持久化到磁盤中:
- 事務提交:當事務提交時,log buffer里redo log會按照innodb_flush_log_at_trx_commit的刷盤時機將數(shù)據(jù)持久化到磁盤中。
- redo log buffer空間不足:log buffer中的redo log已經(jīng)占滿該緩沖區(qū)一半時,緩沖區(qū)數(shù)據(jù)就會被刷到磁盤中。
- 事務日志緩沖區(qū)已滿:InnoDB使用一個事務日志緩沖區(qū)(transaction log buffer)存儲事務redo log的日志條目,當該緩存區(qū)已滿時,就會觸發(fā)日志刷新將日志寫入磁盤中。
- 后臺線程定時刷盤:innodb后臺線程會每隔1s調用操作系統(tǒng)fsync函數(shù)將redolog數(shù)據(jù)刷盤。
- checkpoint:線程會定時執(zhí)行一個checkpoint,將buffer pool已經(jīng)刷盤持久化到物理文件的數(shù)據(jù)對應的redo log設置為可被覆蓋(保證日志空間可以循環(huán)復用),這期間對應的redo log數(shù)據(jù)就會被寫入磁盤中。
- 服務器關閉:MySQL服務正常關閉時,這些緩沖區(qū)的數(shù)據(jù)就會寫入到磁盤中。
redo log的刷盤策略
上文事務提交時提到一個刷盤策略的概念,實際上寫入磁盤的時機是由MySQL系統(tǒng)參數(shù)設置決定的,我們可以鍵入下面這條SQL查看innodb_flush_log_at_trx_commit這個參數(shù)的設定值:
SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';以筆者的MySQL8為例,默認情況下這個參數(shù)值為1:

當這個值為0時,每次進行修改寫入到redo log buffer,然后redo log buffer會將數(shù)據(jù)寫到page cache中,由log thread每個1s調用操作系統(tǒng)函數(shù)fsync將數(shù)據(jù)寫入到redo.file中。很可能因為服務器崩潰或者宕機導致丟失1s的數(shù)據(jù)。

1為默認值,當參數(shù)值設置為1時, 每次進行修改操作后將數(shù)據(jù)寫入到redo log buffer中,一旦事務被提交,就會自動調用操作系統(tǒng)函數(shù)fsync將數(shù)據(jù)寫入的磁盤中的redo.file文件中。若設置為這個級別,當服務器宕機,若當前事務沒有提交,這部分數(shù)據(jù)丟失也無妨,事務提交的話,那么這個操作就會被寫到磁盤中,照樣可以恢復。

配置為2時,每當事務提交后,redo log就會刷入內核緩沖區(qū),這些數(shù)據(jù)具體何時刷盤則交由操作系統(tǒng)決定,這種情況在MySQL宕機情況下不會造成數(shù)據(jù)丟失,一旦操作系統(tǒng)崩潰則可能會造成內核緩沖區(qū)的redo log數(shù)據(jù)丟失,導致進行數(shù)據(jù)備份還原時丟失一部分數(shù)據(jù):

redo log的日志文件組
redo log并不是單指一個文件,它是由一組日志文件構成的,如下圖所示,這些文件大小都是一樣的,寫入操作時依次從從1開始寫,文件1寫滿了,就將數(shù)據(jù)寫到文件2,最后寫到文件4。
redolog通過write pos標記當前寫入的位置,每次完成寫入write pos標志位后移,一旦write pos和checkpoint相遇時就說明文件滿了,此時innodb就會通過讓checkpoint往后移進行一些空間數(shù)據(jù)擦除,以此來保證一個足夠空間容納新數(shù)據(jù)。

為什么InnoDB不直接將數(shù)據(jù)寫入磁盤
頁是操作系統(tǒng)的基本單位,一頁差不多16kb,而我們每次操作的數(shù)據(jù)可能也就x byte,為了x byte的數(shù)據(jù)操作將一頁的數(shù)據(jù)進行同步持久化實在有些大材小用了,所以通過redo log buffer記錄修改內容,通過刷盤策略進行數(shù)據(jù)刷盤更新,由此提升數(shù)據(jù)庫的并發(fā)能力:

bin.log和redo.log對應的二階段提交
經(jīng)常有讀者面試被問道的為什么我有了redo.log,你還需要bin log呢?而且這兩個日志我到底要先寫哪個才能保證主從數(shù)據(jù)庫的一致性呢?
對此我們不妨用反正法來說明:
- 假設我們先寫bin.log,當事務提交后bin.log寫入成功,結果再寫redo.log期間,數(shù)據(jù)庫掛了。重啟恢復后,主數(shù)據(jù)庫根據(jù)早期redo.log(我們的redo.log沒寫入)恢復到bin log寫入前的樣子,而從數(shù)據(jù)庫已經(jīng)根據(jù)bin.log同步到了一份數(shù)據(jù),最終從數(shù)據(jù)庫比主數(shù)據(jù)庫多了一條數(shù)據(jù)。

- 我們再假設寫redo log,假設事務執(zhí)行期間我們就寫了redo log,在事務提交之后寫bin log數(shù)據(jù)庫掛了,我們重啟數(shù)據(jù)庫后主主庫恢復。主庫根據(jù)redo log進行災備恢復,將我們更新的數(shù)據(jù)同時恢復回來,而從庫根據(jù)bin log進行數(shù)據(jù)同步時,并沒有察覺到主庫剛剛寫入的數(shù)據(jù),這就導致了從庫比主庫少了一條數(shù)據(jù)。

所以MySQL設計者提出了二階段提交的概念,整體步驟為:
- 在事務開始時,先寫redo-log(prepare)。
- 事務提交時,再寫bin log。
- 事務提交成功,再寫redo-log(commit)。

有了這樣一個整體步驟我們不妨用兩種情況來舉個例子演示一下二階段提交如何保證數(shù)據(jù)一致性。
假設我們有一張user表,這張表只有id、name兩個字段。我們執(zhí)行如下SQL:
update user set name='aa' where id=1;假如我們在redo.log提交時數(shù)據(jù)庫宕機,二階段是如何保證數(shù)據(jù)一致性的呢?
首先數(shù)據(jù)庫重啟恢復,然后主庫發(fā)現(xiàn)redo.log日志處于prepare而且bin.log也沒有寫入,所以一切恢復到之前的樣子(事務回滾),而從庫對此無感,同步時也是同步成操作失敗之前的樣子,一切風平浪靜:

假如我們bin.log進行commit成功之后數(shù)據(jù)庫宕機,二階段提交是如何保證數(shù)據(jù)庫一致性的呢?還是老規(guī)矩:
- 數(shù)據(jù)庫重啟恢復,然后主庫發(fā)現(xiàn)bin.log有個commit成功的數(shù)據(jù)(事務是完整的)
- 然redo.log處于prepare階段,但是我們還是可以根據(jù)情況推斷出有個當前主庫有個commit成功的事務,所以redo.log會根據(jù)bin.log將redo.log設置為commit
- 從庫已根據(jù)主庫的bin.log發(fā)現(xiàn)有新增一條新數(shù)據(jù),由此同步一條更新數(shù)據(jù),雙方都有了一條新數(shù)據(jù),數(shù)據(jù)庫一致性由此保證:


























