前言
說到MySQL,有兩塊日志一定繞不開,一個(gè)是InnoDB存儲(chǔ)引擎的redo log(重做日志),另一個(gè)是MySQL Servce層的 binlog(歸檔日志)。
只要是數(shù)據(jù)更新操作,就一定會(huì)涉及它們,今天就來聊聊redo log(重做日志)。
redo log
redo log(重做日志)是InnoDB存儲(chǔ)引擎獨(dú)有的,它讓MySQL擁有了崩潰恢復(fù)能力。
比如MySQL實(shí)例掛了或宕機(jī)了,重啟時(shí),InnoDB存儲(chǔ)引擎會(huì)使用redo log恢復(fù)數(shù)據(jù),保證數(shù)據(jù)的持久性與完整性。
上一篇中阿星講過,MySQL中數(shù)據(jù)是以頁(yè)為單位,你查詢一條記錄,會(huì)從硬盤把一頁(yè)的數(shù)據(jù)加載出來,加載出來的數(shù)據(jù)叫數(shù)據(jù)頁(yè),會(huì)放入到Buffer Pool中。
后續(xù)的查詢都是先從Buffer Pool中找,沒有命中再去硬盤加載,減少硬盤IO開銷,提升性能。
更新表數(shù)據(jù)的時(shí)候,也是如此,發(fā)現(xiàn)Buffer Pool里存在要更新的數(shù)據(jù),就直接在Buffer Pool里更新。
然后會(huì)把“在某個(gè)數(shù)據(jù)頁(yè)上做了什么修改”記錄到重做日志緩存(redo log buffer)里,接著刷盤到redo log文件里。
理想情況,事務(wù)一提交就會(huì)進(jìn)行刷盤操作,但實(shí)際上,刷盤的時(shí)機(jī)是根據(jù)策略來進(jìn)行的。
小貼士:每條redo記錄由“表空間號(hào)+數(shù)據(jù)頁(yè)號(hào)+偏移量+修改數(shù)據(jù)長(zhǎng)度+具體修改的數(shù)據(jù)”組成
刷盤時(shí)機(jī)
InnoDB存儲(chǔ)引擎為redo log的刷盤策略提供了innodb_flush_log_at_trx_commit參數(shù),它支持三種策略
設(shè)置為0的時(shí)候,表示每次事務(wù)提交時(shí)不進(jìn)行刷盤操作
設(shè)置為1的時(shí)候,表示每次事務(wù)提交時(shí)都將進(jìn)行刷盤操作(默認(rèn)值)
設(shè)置為2的時(shí)候,表示每次事務(wù)提交時(shí)都只把redo log buffer內(nèi)容寫入page cache
另外InnoDB存儲(chǔ)引擎有一個(gè)后臺(tái)線程,每隔1秒,就會(huì)把redo log buffer中的內(nèi)容寫到文件系統(tǒng)緩存(page cache),然后調(diào)用fsync刷盤。
也就是說,一個(gè)沒有提交事務(wù)的redo log記錄,也可能會(huì)刷盤。
為什么呢?
因?yàn)樵谑聞?wù)執(zhí)行過程redo log記錄是會(huì)寫入redo log buffer中,這些redo log記錄會(huì)被后臺(tái)線程刷盤。
除了后臺(tái)線程每秒1次的輪詢操作,還有一種情況,當(dāng)redo log buffer占用的空間即將達(dá)到innodb_log_buffer_size一半的時(shí)候,后臺(tái)線程會(huì)主動(dòng)刷盤。
下面是不同刷盤策略的流程圖
innodb_flush_log_at_trx_commit=0
為0時(shí),如果MySQL掛了或宕機(jī)可能會(huì)有1秒數(shù)據(jù)的丟失。
innodb_flush_log_at_trx_commit=1
為1時(shí), 只要事務(wù)提交成功,redo log記錄就一定在硬盤里,不會(huì)有任何數(shù)據(jù)丟失。
如果事務(wù)執(zhí)行期間MySQL掛了或宕機(jī),這部分日志丟了,但是事務(wù)并沒有提交,所以日志丟了也不會(huì)有損失。
innodb_flush_log_at_trx_commit=2
為2時(shí), 只要事務(wù)提交成功,redo log buffer中的內(nèi)容只寫入文件系統(tǒng)緩存(page cache)。
如果僅僅只是MySQL掛了不會(huì)有任何數(shù)據(jù)丟失,但是宕機(jī)可能會(huì)有1秒數(shù)據(jù)的丟失。
日志文件組
硬盤上存儲(chǔ)的redo log日志文件不只一個(gè),而是以一個(gè)日志文件組的形式出現(xiàn)的,每個(gè)的redo日志文件大小都是一樣的。
比如可以配置為一組4個(gè)文件,每個(gè)文件的大小是1GB,整個(gè)redo log日志文件組可以記錄4G的內(nèi)容。
它采用的是環(huán)形數(shù)組形式,從頭開始寫,寫到末尾又回到頭循環(huán)寫,如下圖所示。
在個(gè)日志文件組中還有兩個(gè)重要的屬性,分別是write pos、checkpoint
write pos是當(dāng)前記錄的位置,一邊寫一邊后移
checkpoint是當(dāng)前要擦除的位置,也是往后推移
每次刷盤redo log記錄到日志文件組中,write pos位置就會(huì)后移更新。
每次MySQL加載日志文件組恢復(fù)數(shù)據(jù)時(shí),會(huì)清空加載過的redo log記錄,并把checkpoint后移更新。
write pos和checkpoint之間的還空著的部分可以用來寫入新的redo log記錄。
如果write pos追上checkpoint,表示日志文件組滿了,這時(shí)候不能再寫入新的redo log記錄,MySQL得停下來,清空一些記錄,把checkpoint推進(jìn)一下。
本文到此就結(jié)束了,下篇會(huì)聊聊binlog(歸檔日志)。
小結(jié)
相信大家都知道redo log的作用和它的刷盤時(shí)機(jī)、存儲(chǔ)形式。
現(xiàn)在我們來思考一問題,只要每次把修改后的數(shù)據(jù)頁(yè)直接刷盤不就好了,還有redo log什么事。
它們不都是刷盤么?差別在哪里?
1 Byte = 8bit
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
實(shí)際上,數(shù)據(jù)頁(yè)大小是16KB,刷盤比較耗時(shí),可能就修改了數(shù)據(jù)頁(yè)里的幾Byte數(shù)據(jù),有必要把完整的數(shù)據(jù)頁(yè)刷盤嗎?
而且數(shù)據(jù)頁(yè)刷盤是隨機(jī)寫,因?yàn)橐粋€(gè)數(shù)據(jù)頁(yè)對(duì)應(yīng)的位置可能在硬盤文件的隨機(jī)位置,所以性能是很差。
如果是寫redo log,一行記錄可能就占幾十Byte,只包含表空間號(hào)、數(shù)據(jù)頁(yè)號(hào)、磁盤文件偏移量、更新值,再加上是順序?qū)?,所以刷盤速度很快。
所以用redo log形式記錄修改內(nèi)容,性能會(huì)遠(yuǎn)遠(yuǎn)超過刷數(shù)據(jù)頁(yè)的方式,這也讓數(shù)據(jù)庫(kù)的并發(fā)能力更強(qiáng)。
其實(shí)內(nèi)存的數(shù)據(jù)頁(yè)在一定時(shí)機(jī)也會(huì)刷盤,我們把這稱為頁(yè)合并,講Buffer Pool的時(shí)候會(huì)對(duì)這塊細(xì)說
責(zé)任編輯:haq
-
數(shù)據(jù)
+關(guān)注
關(guān)注
8文章
6819瀏覽量
88743 -
存儲(chǔ)
+關(guān)注
關(guān)注
13文章
4226瀏覽量
85580 -
MySQL
+關(guān)注
關(guān)注
1文章
798瀏覽量
26401
原文標(biāo)題:聊聊 redo log 是什么?
文章出處:【微信號(hào):DBDevs,微信公眾號(hào):數(shù)據(jù)分析與開發(fā)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論