MySQL事務(wù)未提交Redolog能持久化到磁盤嗎?
今天的文章內(nèi)容圍繞一位網(wǎng)友的評(píng)論去展開,在看完小許文章【結(jié)合MySQL更新流程看 undolog、redolog、binlog】,他提出了這么一個(gè)問題,如下:
圖片
換個(gè)方式提取出他想問的:可以理解為如果在redolog持久化過程中,意外情況導(dǎo)致事務(wù)未提交,那是不是redolog就寫入不了磁盤了?
本期內(nèi)容就從這個(gè)問題進(jìn)行展開要講的內(nèi)容!
我們知道持久化的目的是可以在數(shù)據(jù)丟失后進(jìn)行恢復(fù),保證數(shù)據(jù)不丟失,對(duì)于MySQL來說只要 binlog 和 redolog 都能正確持久化到磁盤上,就可以保證數(shù)據(jù)不丟失了。
?? 那意外情況導(dǎo)致事務(wù)還沒提交的時(shí)候,redolog 能不能被持久化到磁盤呢?
先公布答案,確實(shí)有可能會(huì)!
為什么會(huì)有這種可能呢,難道是被動(dòng)刷盤了?先不著急想象,我們接著往下看,這個(gè)問題今天必須拿下!
圖片
redo log可能存在的位置
沒看過開頭提到的文章建議返回去看下,這里再進(jìn)行下核心知識(shí)點(diǎn)的回憶。
redo log 其實(shí)記錄的是此次事務(wù)「完成后」的數(shù)據(jù)狀態(tài),記錄的是更新之后的值。
我們來回顧看下redolog的寫入流程:
圖片
1. 修改操作時(shí)先將原始數(shù)據(jù)從磁盤中讀入內(nèi)存中來,修改數(shù)據(jù),如圖中的臟頁
2. 此時(shí)產(chǎn)生日志寫入redo logbuffer,記錄的是數(shù)據(jù)被修改后的值
3. 當(dāng)事務(wù)commit時(shí),將redo logbuffer中的內(nèi)容采用追加方式刷新到redo logfile
4. 調(diào)用fsync將修改的數(shù)據(jù)刷新到磁盤中
也就是說redolog可能存在于三種位置狀態(tài):
圖片
redolog buffer:
寫入redo log buffer就用到了的WAL(Write-Ahead Logging)技術(shù),日志先寫入redo log buffer緩沖區(qū)
page cache:
page cache是文件系統(tǒng)緩沖,如果是寫到磁盤,但是沒有持久化(fsync),物理上是在文件系統(tǒng)的page cache里面
硬盤disk:
從page cache 持久化到磁盤,也就是磁盤中的redo log file中,你在data目錄中看到的ib_logfile文件就是實(shí)際的redo log日志文件,它以文件組的形式出現(xiàn)的。這些文件以ib_logfile[數(shù)字](數(shù)字可以是0、1、2..)的形式進(jìn)行命名。
事務(wù)提交的過程
一般來說事務(wù)的提交也應(yīng)該有以下三個(gè)過程:
圖片
寫磁盤策略
緩存在 redo log buffer 里的 redo log 是在內(nèi)存中的,最終是要刷到磁盤中。
?? 那么redo log是如何被控制寫入刷入磁盤的呢?
這就涉及到redo log的刷盤策略了
InnoDB通過innodb_flush_log_at_trx_commit 參數(shù)可以控制策略,該參數(shù)控制 commit 提交事務(wù)時(shí),如何將 redo log buffer中的日志刷新到 redo log file 中,它支持設(shè)定0,1, 2也就是說支持三種策略設(shè)置。
這個(gè)策略我們可以用參數(shù)設(shè)置:
show variables like 'innodb_flush_log_at_trx_commit'
//默認(rèn)情況下 innodb_flush_log_at_trx_commit值是1
Innodb存儲(chǔ)引擎有一個(gè)后臺(tái)線程,每隔1秒,就會(huì)把 redo log buffer 中的內(nèi)容寫到文件系統(tǒng)緩存(Page Cache),然后調(diào)用fsync進(jìn)行刷入到磁盤的操作。
延遲寫
設(shè)置為0(延遲寫) :每次事務(wù)提交時(shí)不主動(dòng)進(jìn)行刷盤操作,redo log依然留在redo log buffer中,然后后臺(tái)進(jìn)程每秒寫入page cache中,然后持久化到磁盤中。
圖片
實(shí)時(shí)寫,實(shí)時(shí)刷
設(shè)置為1 (實(shí)時(shí)寫,實(shí)時(shí)刷):每次事務(wù)提交時(shí)都會(huì)直接將緩存在redo log buffer中的redo log直接持久化到磁盤中( 默認(rèn)值 )。
圖片
實(shí)時(shí)寫,延時(shí)刷
設(shè)置為2(實(shí)時(shí)寫,延時(shí)刷) :表示每次事務(wù)提交時(shí)都只把 redo log buffer 內(nèi)容寫入 page cache,不進(jìn)行同步,由os自己決定什么時(shí)候同步到磁盤文件。
圖片
事務(wù)未提交寫磁盤的情況
看了redo log可能存在的狀態(tài)和位置,以及寫盤策略,那跟事務(wù)是否提交redo log能否寫入磁盤有啥關(guān)系呢。
那我們看下面幾種情況是不是在事務(wù)沒提交的時(shí)候也可能會(huì)寫入到磁盤呢!
后臺(tái)線程每隔1s刷新
上面我們說到InnoDB 有一個(gè)后臺(tái)線程,每隔 1 秒輪詢一次,具體的操作是這樣的:調(diào)用 write 將 redolog buffer 中的日志寫到文件系統(tǒng)的 page cache,然后調(diào)用 fsync 持久化到磁盤。
那么寫入到redolog buffer中的redo log在事務(wù)沒提交的時(shí)候,可能就會(huì)后臺(tái)線程在持久化的時(shí)候被一起持久化到磁盤中。
其他事務(wù)提交成功
我們?cè)谠O(shè)置寫盤策略的時(shí)候 innodb_flush_log_at_trx_commit 設(shè)置為1,在每次事務(wù)提交的時(shí)候都會(huì)直接將緩存在redo log buffer中的redo log直接持久化到磁盤中。
舉個(gè)栗子,事務(wù) A 執(zhí)行到一半,此時(shí) redolog 到 redolog buffer 中,這時(shí)候有另外一個(gè)事務(wù) B 提交,事務(wù) B 要把 redolog buffer 里的日志全部持久化到磁盤,這時(shí)候就會(huì)帶上是不是事務(wù) A 在 redolog buffer 里的日志一起持久化到磁盤。
(⊙o⊙)…
redo log buffer 空間快滿了
另一種說法是當(dāng)redo log buffer 占用的空間達(dá)到 redolog buffer 大小一半的時(shí)候,后臺(tái)線程會(huì)主動(dòng)寫盤。
redo log buffer 占用空間由參數(shù) innodb_log_buffer_size 控制,默認(rèn)是 8MB
但是這個(gè)寫盤動(dòng)作只是 write 到了文件系統(tǒng)的 page cache,仍然是在內(nèi)存中,并沒有調(diào)用 fsync 真正落盤。
??朋友們下次當(dāng)面試官問你:事務(wù)還沒提交的時(shí)候,redo log 能不能被持久化到磁盤呢?
你應(yīng)該知道如何回答了吧,哈哈,拿下!