聊聊redo log是什麼?

-聊聊redo log是什麼?

前言

說到MySQL,有兩塊日誌一定繞不開,一個是InnoDB存儲引擎的redo log(重做日誌),另一個是MySQL Servce層的 binlog(歸檔日誌)。

只要是數據更新操作,就一定會涉及它們,今天就來聊聊redo log(重做日誌)。

redo log

redo log(重做日誌)是InnoDB存儲引擎獨有的,它讓MySQL擁有了崩潰恢復能力。

比如MySQL實例掛了或宕機了,重啓時,InnoDB存儲引擎會使用redo log恢復數據,保證數據的持久性與完整性。

上一篇中阿星講過,MySQL中數據是以頁爲單位,你查詢一條記錄,會從硬盤把一頁的數據加載出來,加載出來的數據叫數據頁,會放入到Buffer Pool中。

後續的查詢都是先從Buffer Pool中找,沒有命中再去硬盤加載,減少硬盤IO開銷,提升性能。

更新表數據的時候,也是如此,發現Buffer Pool裏存在要更新的數據,就直接在Buffer Pool裏更新。

然後會把“在某個數據頁上做了什麼修改”記錄到重做日誌緩存(redo log buffer)裏,接着刷盤到redo log文件裏。

理想情況,事務一提交就會進行刷盤操作,但實際上,刷盤的時機是根據策略來進行的。

小貼士:每條redo記錄由“表空間號+數據頁號+偏移量+修改數據長度+具體修改的數據”組成

刷盤時機

InnoDB存儲引擎爲redo log的刷盤策略提供了innodb_flush_log_at_trx_commit參數,它支持三種策略

  • 設置爲0的時候,表示每次事務提交時不進行刷盤操作
  • 設置爲1的時候,表示每次事務提交時都將進行刷盤操作(默認值)
  • 設置爲2的時候,表示每次事務提交時都只把redo log buffer內容寫入page cache

另外InnoDB存儲引擎有一個後臺線程,每隔1秒,就會把redo log buffer中的內容寫到文件系統緩存(page cache),然後調用fsync刷盤。

也就是說,一個沒有提交事務的redo log記錄,也可能會刷盤。

爲什麼呢?

因爲在事務執行過程redo log記錄是會寫入redo log buffer中,這些redo log記錄會被後臺線程刷盤。

除了後臺線程每秒1次的輪詢操作,還有一種情況,當redo log buffer佔用的空間即將達到innodb_log_buffer_size一半的時候,後臺線程會主動刷盤。

下面是不同刷盤策略的流程圖

innodb_flush_log_at_trx_commit=0

0時,如果MySQL掛了或宕機可能會有1秒數據的丟失。

innodb_flush_log_at_trx_commit=1

1時, 只要事務提交成功,redo log記錄就 一定在硬盤裏,不會有任何數據丟失。

如果事務執行期間MySQL掛了或宕機,這部分日誌丟了,但是事務並沒有提交,所以日誌丟了也不會有損失。

innodb_flush_log_at_trx_commit=2

2時, 只要事務提交成功,redo log buffer中的內容只寫入文件系統緩存(page cache)。

如果僅僅只是MySQL掛了不會有任何數據丟失,但是宕機可能會有1秒數據的丟失。

日誌文件組

硬盤上存儲的redo log日誌文件不只一個,而是以一個日誌文件組的形式出現的,每個的redo日誌文件大小都是一樣的。

比如可以配置爲一組4個文件,每個文件的大小是1GB,整個redo log日誌文件組可以記錄4G的內容。

它採用的是環形數組形式,從頭開始寫,寫到末尾又回到頭循環寫,如下圖所示。

在個日誌文件組中還有兩個重要的屬性,分別是write pos、checkpoint

  • write pos是當前記錄的位置,一邊寫一邊後移
  • checkpoint是當前要擦除的位置,也是往後推移

每次刷盤redo log記錄到日誌文件組中,write pos位置就會後移更新。

每次MySQL加載日誌文件組恢復數據時,會清空加載過的redo log記錄,並把checkpoint後移更新。

write poscheckpoint之間的還空着的部分可以用來寫入新的redo log記錄。

如果write pos追上checkpoint,表示日誌文件組滿了,這時候不能再寫入新的redo log記錄,MySQL得停下來,清空一些記錄,把checkpoint推進一下。

本文到此就結束了,下篇會聊聊binlog(歸檔日誌)。

小結

相信大家都知道redo log的作用和它的刷盤時機、存儲形式。

現在我們來思考一問題,只要每次把修改後的數據頁直接刷盤不就好了,還有redo log什麼事。

它們不都是刷盤麼?差別在哪裏?

1 Byte = 8bit
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
複製代碼

實際上,數據頁大小是16KB,刷盤比較耗時,可能就修改了數據頁裏的幾Byte數據,有必要把完整的數據頁刷盤嗎?

而且數據頁刷盤是隨機寫,因爲一個數據頁對應的位置可能在硬盤文件的隨機位置,所以性能是很差。

如果是寫redo log,一行記錄可能就佔幾十Byte,只包含表空間號、數據頁號、磁盤文件偏移 量、更新值,再加上是順序寫,所以刷盤速度很快。

所以用redo log形式記錄修改內容,性能會遠遠超過刷數據頁的方式,這也讓數據庫的併發能力更強。

其實內存的數據頁在一定時機也會刷盤,我們把這稱爲頁合併,講Buffer Pool的時候會對這塊細說

站在巨人的肩膀上

  • 《MySQL實戰45講》
  • 《從零開始帶你成爲MySQL實戰優化高手》
  • 《MySQL是怎樣運行的:從根兒上理解MySQL》
  • 《MySQL技術Innodb存儲引擎》

MySQL好文推薦

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