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