-聊聊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 pos
和checkpoint
之間的還空着的部分可以用來寫入新的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存儲引擎》