一、寫作背景
大家都清楚,日志是 MySQL數(shù)據(jù)庫的重要組成部分,記錄著數(shù)據(jù)庫運(yùn)行期間各種狀態(tài)信息。MySQL日志主要包括錯(cuò)誤日志、查詢?nèi)罩?/strong>、慢查詢?nèi)罩?/strong>、二進(jìn)制日志(binlog)和事務(wù)日志(redo log、undo log)幾大類。
其中,二進(jìn)制日記和事務(wù)日記尤為重要,一直被人重視、深入研究;可是事實(shí)很殘忍,重視或者說大多數(shù)人一般都是了解個(gè)表面,真正懂得人并不多。真想攻破這兩塊日記必須下血本,而且還不一定能攻破。但是不要緊,為了讓你們省下血本還能順利攻破這兩塊日記,我連續(xù)研究幾周MySQL日記,最終肝出了這篇文章。
二、文章指引
文章指導(dǎo):文章第三節(jié)內(nèi)容切莫跳過,但如果覺得第四、第五、第六和第七節(jié)沒意思或者已經(jīng)有了概念,直接進(jìn)入文章第八節(jié)一舉攻破拿下。
文章方向:理論、原理篇。
三、必要概念字典介紹
基礎(chǔ)不牢地動(dòng)山搖,還是常規(guī)套路,先把必要知識(shí)普及/溫習(xí)一遍,當(dāng)后續(xù)文章出現(xiàn)疑慮反過來看下這些概念字典,說不定能 “柳暗花明又一村” 呢?
寫了又寫,想了又想,糾結(jié)了好久,這部分知識(shí)確實(shí)有點(diǎn)多,最后還是決定將這些必要概念字典單獨(dú)分出一個(gè)文章,后續(xù)打算用截圖方式引入各個(gè)章節(jié)中,建議遇到不懂名詞查閱一下字典。
圖1:進(jìn)階知識(shí)部分示意圖
四、認(rèn)識(shí)二進(jìn)制日記(Binlog)
4.1 Binlog概念
Binlog 是邏輯日記,用于記錄數(shù)據(jù)庫執(zhí)行的寫入操作(查詢不記錄)信息,Server層記錄和引擎層無關(guān),并且是以追加方式進(jìn)行寫入,可以通過參數(shù) max_binlog_size 設(shè)置每個(gè)Binlog文件的大小,文件大小達(dá)到設(shè)定值時(shí)會(huì)生成新的文件來保存日記。
4.2 Binlog 作用
在實(shí)際應(yīng)用中,主要用在兩個(gè)場(chǎng)景:主從復(fù)制和數(shù)據(jù)恢復(fù)
- 主從復(fù)制場(chǎng)景:在Master主端開啟Binlog,將Binlog發(fā)生到各個(gè)Slave從端,Slave從端重放Binlog從而達(dá)到主從數(shù)據(jù)一致
- 數(shù)據(jù)恢復(fù)場(chǎng)景:通過使用 mysqlbinlog 工具來恢復(fù)數(shù)據(jù)
4.3 Binlog 記錄過程及刷盤時(shí)機(jī)
Binlog何時(shí)記錄將在第六點(diǎn)進(jìn)行介紹,大致記錄過程是先寫B(tài)inlog Buffer,然后通過刷盤時(shí)機(jī),控制刷入OS Buffer,控制fsync()進(jìn)行寫入Binlog File日記磁盤的過程。
對(duì)于Binlog,MySQL是通過參數(shù)sync_binlog參數(shù)來控制刷盤時(shí)機(jī),取值是0、1和N三種值。0表示由系統(tǒng)自行判斷何時(shí)調(diào)用sync()寫入磁盤;1表示每次事務(wù)commit都要調(diào)用fsync()寫入磁盤;N表示每N個(gè)事務(wù),才會(huì)調(diào)用fsync()寫入磁盤。
圖2:內(nèi)存和磁盤日記結(jié)構(gòu)圖
4.4 Binlog 記錄格式
MySQL5.7.7版本之前默認(rèn)格式是STATEMENT,版本之后默認(rèn)是ROW,可以通過參數(shù) binlog-format指定。
五、認(rèn)識(shí)事務(wù)日記(Undo log)
5.1 Undo log 概念
Undo log是邏輯日記、回滾日記。比如一條修改+3的邏輯語句,Undo log會(huì)記錄對(duì)應(yīng)一條-3的邏輯日記,一條插入語句則會(huì)記錄一條刪除語句,這樣發(fā)生錯(cuò)誤時(shí),根據(jù)執(zhí)行Undo log就可以回滾到事務(wù)之前的數(shù)據(jù)狀態(tài)。
5.2 Undo log 作用
- 回滾數(shù)據(jù):當(dāng)程序發(fā)生異常錯(cuò)誤時(shí)等,根據(jù)執(zhí)行Undo log就可以回滾到事務(wù)之前的數(shù)據(jù)狀態(tài),保證原子性,要么成功要么失敗。
- MVCC一致性視圖:通過Undo log找到對(duì)應(yīng)的數(shù)據(jù)版本號(hào),是保證MVCC視圖的一致性的必要條件。
5.3 Undo log 記錄過程及刷盤時(shí)機(jī)
刷盤過程及時(shí)機(jī)類似于Binlog和Redo,可以參考Redo log刷盤時(shí)機(jī)章節(jié)給出的圖片,已經(jīng)體現(xiàn)出來了。
5.4 Undo log 總結(jié)
Undo log日記內(nèi)容不是很多,重點(diǎn)是回滾和多版本控制MVCC那塊。此外,我記得印象筆記深刻的是長事務(wù)會(huì)導(dǎo)致日記過多,這個(gè)日記就是Undo log。因?yàn)殚L事務(wù)存在,導(dǎo)致需要保存很多視圖快照,其實(shí)這里就是涉及到Undo log何時(shí)刪除和生成的問題,當(dāng)時(shí)糾結(jié)好久,其實(shí)很簡(jiǎn)單。生成是事務(wù)開始后寫Redo log之前生成,當(dāng)沒有事務(wù)需要用到Undo log時(shí)就會(huì)被刪除。舉個(gè)例子,如果事務(wù)A一直存活,那么事務(wù)A之后產(chǎn)生的事務(wù)B、C...等等就算提交了,也不會(huì)被刪除,因?yàn)槭聞?wù)A需要用到B、C...事務(wù)去找A的版本。所以避免長事務(wù)可以減少Undo log日記量,當(dāng)然還可以提高性能。
六、認(rèn)識(shí)事務(wù)日記 (Redo log)
6.1 Redo log 概念
Redo log 是重做日記,屬于InnoDB引擎的日記。是物理日記,日記記錄的內(nèi)容的是數(shù)據(jù)頁的更改,這個(gè)頁 “做了什么改動(dòng)”。如:add xx記錄 to Page1,向數(shù)據(jù)頁P(yáng)age1增加一個(gè)記錄。
6.2 Redo log 作用
- 前滾操作:具備crash-safe能力,提供斷電重啟時(shí)解決事務(wù)丟失數(shù)據(jù)問題。
- 提高性能:先寫Redo log記錄更新。當(dāng)?shù)鹊接锌臻e線程、內(nèi)存不足、Redo log滿了時(shí) “刷臟”。寫Redo log是順序?qū)懭耄⑴K是隨機(jī)寫,節(jié)省的是隨機(jī)寫磁盤的 IO 消耗(轉(zhuǎn)成順序?qū)懀?/strong>所以性能得到提升。此技術(shù)稱為WAL技術(shù):Write-Ahead Logging,它的關(guān)鍵點(diǎn)就是先寫日記磁盤,再寫數(shù)據(jù)磁盤。
6.3 Redo log 的兩階段提交
更新內(nèi)存后引擎層寫Redo log將狀態(tài)改成prepare為預(yù)提交第一階段,Server層寫B(tài)inlog,將狀態(tài)改成commit為提交第二階段。兩階段提交可以確保Binlog和Redo log數(shù)據(jù)一致性。
6.4 Redo log 容災(zāi)恢復(fù)過程
MySQL的處理過程如下
- 判斷redo log是否完整,如果判斷是完整(commit)的,直接用Redo log恢復(fù)
- 如果redo log只是預(yù)提交prepare但不是commit狀態(tài),這個(gè)時(shí)候就會(huì)去判斷binlog是否完整,如果完整就提交Redo log,用Redo log恢復(fù),不完整就回滾事務(wù),丟棄數(shù)據(jù)。
只有在redo log狀態(tài)為prepare時(shí),才會(huì)去檢查binlog是否存在,否則只校驗(yàn)redo log是否是 commit就可以啦。 怎么檢查binlog:一個(gè)完整事物binlog結(jié)尾有固定的格式。
6.5 Redo log 刷盤時(shí)機(jī)
Undo log的刷盤時(shí)機(jī)和Redo log差不多,但是對(duì)于Undo log我沒找到對(duì)應(yīng)的刷盤參數(shù)設(shè)計(jì),所以不再提。Redo log每次先寫入Redo Log Buffer中,然后通過刷盤時(shí)機(jī)控制刷入OS Buffer時(shí)間和刷入日記磁盤的時(shí)間。
圖3:內(nèi)存和磁盤日記結(jié)構(gòu)圖
在Undo Log中,MySQL是通過參數(shù)innodb_flush_log_at_trx_commit來控制刷盤時(shí)機(jī),取值是0、1和2三種值。0表示事務(wù)提交后,每秒寫入OS Buffer并調(diào)用fsync()寫入日記磁盤中;1表示每次事務(wù)提交會(huì)寫入OS Buffer并調(diào)用fsync()將日記寫入日記磁盤中。2表示事務(wù)每次提交寫入到OS Buffer,每秒調(diào)用fsync()寫入日記磁盤。可見參數(shù)為1是最安全的,同時(shí)也是默認(rèn)值。
圖4:Redo log刷盤時(shí)機(jī)參數(shù)對(duì)應(yīng)操作圖
6.6 Redo log 存儲(chǔ)方式
圖5:Redo log File環(huán)形存儲(chǔ)結(jié)構(gòu)圖
上圖是日記磁盤的Redo log環(huán)形設(shè)計(jì)圖(從頭寫,寫到結(jié)束又從頭開始寫~循環(huán))。write pos和check point是兩個(gè)指針,write pos指針指向當(dāng)前日記文件寫入的位置,check point指針指向當(dāng)前要擦除的開始位置。圖中綠色部分是可以寫入Redo log地方,每次寫入,write pos指針會(huì)順時(shí)針推進(jìn),當(dāng)然基本不會(huì)與check point指針重合,因?yàn)镸ySQL有這種機(jī)制去實(shí)現(xiàn),每次觸發(fā)檢查點(diǎn)checkpoint,check point會(huì)指針向前推進(jìn),這個(gè)過程就是需要進(jìn)行刷日記和數(shù)據(jù)磁盤,記錄相應(yīng)的LSN,引出難點(diǎn)LSN。
6.7 Redo Log 檢查點(diǎn)
啥時(shí)候會(huì)觸發(fā)檢查點(diǎn)checkpoint,網(wǎng)上找了點(diǎn)資料:啥時(shí)候數(shù)據(jù)庫會(huì)觸發(fā)檢查點(diǎn)checkpoint
圖6:檢查點(diǎn)觸發(fā)時(shí)機(jī)
Checkpoint發(fā)生的時(shí)間、條件及臟頁的選擇等都非常復(fù)雜。而Checkpoint所做的事情無外乎是將緩沖池中的臟頁刷回到磁盤,不同之處在于每次刷新多少頁到磁盤,每次從哪里取臟頁,以及什么時(shí)間觸發(fā)Checkpoint。這些本文不會(huì)去研究。
6.8 Redo Log LSN
LSN這個(gè)概念,比較復(fù)雜,我介紹完你們不一定懂!LSN稱為日志的邏輯序列號(hào)(log sequence number),在innodb存儲(chǔ)引擎中,lsn占用8個(gè)字節(jié)。LSN的值會(huì)隨著日志的寫入而逐漸增大。可以簡(jiǎn)單理解SLN就是記錄從開始到現(xiàn)在已經(jīng)產(chǎn)生了多少字節(jié)的Redo log值。
存儲(chǔ)方式兩個(gè)指針又是通過LSN計(jì)算得到指向位置,因?yàn)長SN記錄的是文件的大小字節(jié),當(dāng)超過文件大小時(shí),需要用取模計(jì)算出這兩個(gè)指針位置,取模使得寫入就會(huì)從頭開始寫,這樣使得兩個(gè)指針在一個(gè)文件中,一直落在循環(huán)位置,你追我趕的過程。這就是Redo log 環(huán)形邏輯思想設(shè)計(jì)實(shí)現(xiàn)。
上面提到LSN比較復(fù)雜,是因?yàn)樗泻芏鄠€(gè)值,輸入命令"show engine innodb status;",可以看到四個(gè)的lsn記錄
圖7:LSN值列表
為了方便識(shí)別,我都為它們重新命名,如下。名詞記不住,后面無法繼續(xù)深入
- 內(nèi)存日記:redo log buffer lsn;磁盤日記:redo log file lsn;
一般關(guān)系為:redo log buffer lsn >= redo log file lsn,如果刷盤時(shí)機(jī)為1,則redo log buffer lsn = redo log file lsn。
- 內(nèi)存數(shù)據(jù)頁:data buffer lsn;數(shù)據(jù)磁盤數(shù)據(jù)頁:data disk lsn;
一般關(guān)系為data buffer lsn > data disk lsn,如果已經(jīng)刷入數(shù)據(jù)磁盤,則data buffer lsn = data disk lsn。
- 檢查點(diǎn):chckpoint lsn;
后面提到檢查點(diǎn)刷盤,數(shù)據(jù)刷盤和日記刷盤(如果有日記刷盤:則說明我假設(shè)的日記刷盤的時(shí)機(jī)設(shè)置值不為1,為1是同步的,即始終redo log buffer lsn = redo log file lsn,不會(huì)由檢查點(diǎn)觸發(fā)刷日記磁盤)。
都說Redo log是環(huán)形記錄,那么怎么記錄的?下面結(jié)合LSN給出記錄過程虛構(gòu)圖,可以對(duì)比6.6 Redo log 存儲(chǔ)方式圖
相關(guān)知識(shí):日記磁盤 + redo log file lsn + checkpoint lsn + 雙指針(write pos、check point)
1-8按時(shí)間順序發(fā)生。1點(diǎn)是假設(shè)最初的狀態(tài);2、3點(diǎn)寫日記磁盤;4點(diǎn)是觸發(fā)了檢查點(diǎn)checkpoint,進(jìn)行刷盤,checkpoint lsn=1開始,刷盤結(jié)束并更新checkpoint lsn=512。在5點(diǎn)、6點(diǎn)已經(jīng)刷過了一循環(huán)內(nèi)存、二循環(huán)內(nèi)存,從頭開始寫入log,兩個(gè)指針指向回到了頭部。第7點(diǎn)也是一個(gè)觸發(fā)checkpoint的過程。9點(diǎn)是假設(shè)沒有更新,最后達(dá)到平衡的結(jié)果,即內(nèi)存中數(shù)據(jù)頁和日記都完成了刷盤。
圖8:Redo Log File存儲(chǔ)過程
整個(gè)流程:
在某些情況下,觸發(fā)checkpoint,觸發(fā)數(shù)據(jù)頁和日志頁刷盤,此時(shí)將內(nèi)存中的臟數(shù)據(jù)---"數(shù)據(jù)臟頁"和"日志臟數(shù)據(jù)" 分別刷到數(shù)據(jù)磁盤和日記磁盤中,而且兩者刷盤速度不一樣。checkpoint會(huì)保護(hù)機(jī)制,當(dāng)數(shù)據(jù)刷盤速度超過日志刷盤時(shí),將會(huì)暫時(shí)停止數(shù)據(jù)刷盤,等待日志刷盤進(jìn)度超過數(shù)據(jù)刷盤。
刷盤時(shí),對(duì)于數(shù)據(jù)磁盤,全部都是在內(nèi)存中,此時(shí)每次刷一個(gè)數(shù)據(jù)頁到內(nèi)存更新數(shù)據(jù)頁也更新了data disk lsn為data buffer lsn(在更新內(nèi)存數(shù)據(jù)頁時(shí),會(huì)更新data buffer lsn)。
對(duì)于日記磁盤,除了要記錄checkpoint lsn的值為檢查點(diǎn) checkpoint的值(必須在結(jié)束時(shí) 直接記錄一個(gè)值,速度很快),這里是針對(duì)日記刷盤時(shí)機(jī)不是1(1是同步緩存刷日記刷盤)時(shí),并且日記還沒刷到日記磁盤需要觸發(fā)將緩存中日記提前刷到日記磁盤中,此時(shí)會(huì)將redo buffer log刷到redo log file中也更新了redo log file lsn為redo log buffer lsn 。
模擬檢查點(diǎn)觸發(fā)前后,整個(gè)流程變化,一個(gè)數(shù)據(jù)頁和日記,數(shù)據(jù)變化及l(fā)sn從179-180的變化圖(刷盤時(shí)機(jī)不為1)
6.9 Redo log 容災(zāi)恢復(fù)過程與LSN
結(jié)合6.4 Redo log 容災(zāi)恢復(fù)過程和6.8的LSN知識(shí),再次細(xì)化6.4的Redo log恢復(fù)過程
重啟innodb時(shí),Redo log完不完整,采用6.4知識(shí)過程。用Redo log恢復(fù),啟動(dòng)數(shù)據(jù)庫時(shí),InnoDB會(huì)掃描數(shù)據(jù)磁盤的數(shù)據(jù)頁data disk lsn和日志磁盤中的checkpoint lsn。兩者相等則從checkpoint lsn點(diǎn)開始恢復(fù),恢復(fù)過程是利用 redo log到buffer pool,直到checkpoint lsn等于redo log file lsn,則恢復(fù)完成。
如果checkpoint lsn 小于 data disk lsn,說明在檢查點(diǎn)觸發(fā)后還沒結(jié)束刷盤時(shí)數(shù)據(jù)庫宕機(jī)了。因?yàn)閏heckpoint lsn最新值是在數(shù)據(jù)刷盤結(jié)束后才記錄的,檢查點(diǎn)之后有一部分?jǐn)?shù)據(jù)已經(jīng)刷入數(shù)據(jù)磁盤,這個(gè)時(shí)候數(shù)據(jù)磁盤已經(jīng)寫入部分的部分恢復(fù)將不會(huì)重做,直接跳到?jīng)]有恢復(fù)的lsn值開始恢復(fù)。
七、了解 ChangeBuffer
7.1 為啥提到ChangeBuffer
為啥本文我會(huì)提到ChangeBuffer呢,其實(shí)很多時(shí)候會(huì)將ChangeBuffer和Redo log搞混,兩者都是巧用內(nèi)存,減少磁盤IO,為了不弄混我覺得有必要專門對(duì)這個(gè)進(jìn)行一個(gè)講解。
7.2 ChangeBuffer概念及作用
下面是我對(duì)ChangeBuffer的簡(jiǎn)單介紹
也就是說對(duì)于更新的操作,如果用到了ChangeBuffer,更新的數(shù)據(jù)所在的數(shù)據(jù)頁如果不在內(nèi)存中,將不用去數(shù)據(jù)磁盤將數(shù)據(jù)頁讀到內(nèi)存,而是將這一次操作記錄在ChangeBuffer中,ChangeBuffer 主要節(jié)省的則是隨機(jī)讀磁盤的 IO 消耗,下次讀取查詢等讀取數(shù)據(jù)頁時(shí)用上ChangeBuffer中的記錄即可。其實(shí)也是一種巧用內(nèi)存的思想。
7.3 ChangeBuffer與Redo log區(qū)別
Redo log 主要節(jié)省的是隨機(jī)寫磁盤的 IO 消耗(轉(zhuǎn)成順序?qū)懀?ChangeBuffer 主要節(jié)省的則是隨機(jī)讀磁盤的 IO 消耗。
這句話怎么理解,看下面:
Redo log 與 ChangeBuffer(含磁盤持久化) 這2個(gè)機(jī)制,不同之處在于優(yōu)化了整個(gè)變更流程的不同階段。
先不考慮Redo log、ChangeBuffer機(jī)制,簡(jiǎn)化抽象一個(gè)更新(insert、update、delete)流程:
- 從磁盤讀取待變更的行所在的數(shù)據(jù)頁,讀入內(nèi)存頁中
- 對(duì)內(nèi)存頁中的行,執(zhí)行變更操作
- 將變更后的數(shù)據(jù)頁,寫入至數(shù)據(jù)磁盤中
其中,流程中的步驟1涉及隨機(jī)讀磁盤IO;步驟3涉及隨機(jī)寫磁盤IO;剛好對(duì)應(yīng)ChangeBuffer和Redo log。
對(duì)那句話的理解答案:
- ChangeBuffer機(jī)制,優(yōu)化了步驟1——避免了隨機(jī)讀磁盤IO ,將不在內(nèi)存中的數(shù)據(jù)頁的操作寫入ChangeBuffer中,而不是將數(shù)據(jù)頁從磁盤讀入內(nèi)存頁中
- Redo log機(jī)制, 優(yōu)化了步驟3——避免了隨機(jī)寫磁盤IO,將隨機(jī)寫磁盤,優(yōu)化為了順序?qū)懘疟P(寫Redo log,確保crash-safe)
7.4 有沒有用到ChangeBuffer對(duì)于Redo log的區(qū)別
Redo log機(jī)制,為了保證crash-safe,一直都會(huì)用到。 有無用到ChangeBuffer機(jī)制,對(duì)于redo log這步的區(qū)別在于—— 用到了ChangeBuffer機(jī)制時(shí),在Redo log中記錄的本次變更,是記錄new change buffer item相關(guān)的信息,而不是直接的記錄物理頁的變更(文章中第八節(jié)都有體現(xiàn)這一過程)。 在我們mysql innodb中, ChangeBuffer機(jī)制不是一直會(huì)被應(yīng)用到,僅當(dāng)待操作的數(shù)據(jù)頁當(dāng)前不在內(nèi)存中,需要先讀磁盤加載數(shù)據(jù)頁時(shí),ChangeBuffer才有用武之地。
7.5 ChangeBuffer的merge過程
除了訪問這個(gè)數(shù)據(jù)也會(huì)觸發(fā) merge 外,系統(tǒng)有后臺(tái)線程會(huì)定期 merge。在數(shù)據(jù)庫正常關(guān)閉(shutdown)的過程中,也會(huì)執(zhí)行 merge 操作。
merge過程做三步
- 從磁盤讀入數(shù)據(jù)頁到內(nèi)存(老版本的數(shù)據(jù)頁);
- 從 change buffer 里找出這個(gè)數(shù)據(jù)頁的 change buffer 記錄 (可能有多個(gè)),依次應(yīng)用,得到新版數(shù)據(jù)頁;
- 寫 redo log。這個(gè) redo log 包含了數(shù)據(jù)的變更和 change buffer 的變更。
八、日記大連貫U-R-B,一舉攻破拿下
前面分別講的是Binlog、Undo log和Redo log,下面將他們都串聯(lián)起來,在一些流程體現(xiàn)全部日記。
同樣,以一些最經(jīng)典的更新語句例子展開說明。
8.1 制造演示數(shù)據(jù)
測(cè)試語句:插入語句+查詢語句,a字段是普通索引
insert into ta(a,b) values(2,5),(7, 5)2、select * from t where a in (2, 7)
假設(shè)原來的數(shù)據(jù)如下圖,數(shù)據(jù)頁page1在內(nèi)存中,page2不在。插入的數(shù)據(jù)(2,5)落在page1,數(shù)據(jù)(7,5)落在page2中。
8.2 假設(shè)沒有日記和ChangeBuffer 示范
先不考慮所有日記及ChangeBuffer機(jī)制,簡(jiǎn)化抽象一個(gè)更新insert流程
- 從磁盤讀取待變更的行所在的數(shù)據(jù)頁,讀入內(nèi)存頁中
- 對(duì)內(nèi)存頁中的行,執(zhí)行變更操作
- 將變更后的數(shù)據(jù)頁,寫入至數(shù)據(jù)磁盤中
8.3 考慮所有日記和ChangeBuffer 示范--現(xiàn)有Innodb流程
過程是 兩階段提交-----日記刷盤------數(shù)據(jù)刷盤(涉及Redo log lsn 和 ChangeBuffer的內(nèi)容)
8.3.1 兩階段提交過程
- 數(shù)據(jù)(2,5)所在頁page1在內(nèi)存中直接更新內(nèi)存;數(shù)據(jù)(7,5)所在頁page2不在內(nèi)存中,記錄change buffer(具有唯一性的索引或者沒有使用change buffer的操作是將磁盤中的數(shù)據(jù)頁讀入內(nèi)存中并做更新)。
- 寫undo日記。先寫緩存,后面根據(jù)刷盤參數(shù)決定何時(shí)刷入磁盤,后面的redo/Binlog都一樣。日記刷盤 在每一個(gè)日記中基本已經(jīng)提到,它和設(shè)置的參數(shù)有關(guān),具體刷盤可以參考上文4.3和6.5章節(jié),下文不會(huì)再展開介紹。
- 寫redo日記(先記在內(nèi)存中的更新,然后記錄在內(nèi)存中的change buffer的改變)
- 日記狀態(tài)改成prepare階段。
- 寫B(tài)inlog日記。
- 提交事務(wù),日記狀態(tài)改成commit階段。
8.3.2 merge 過程
緊接著上文,圖片可上下參考,假設(shè)現(xiàn)在執(zhí)行查詢語句 “select * from t where a in (2, 7)” ,此次查詢索引a=7所在的數(shù)據(jù)頁不在內(nèi)存中,并且上一步更新已經(jīng)在change buffer中有記錄,將會(huì)觸發(fā)merge過程(參考第七章節(jié)7.5)。
- 將page2讀入內(nèi)存
- 依次應(yīng)用change buffer中的記錄,得到最新版數(shù)據(jù)頁
- 寫入redo,之前記錄的changebuffer改動(dòng),現(xiàn)在改成數(shù)據(jù)頁的改動(dòng)
至于changebuffer被應(yīng)用后是刪除還是標(biāo)記,還有redo中原有的記錄changebuffer的改動(dòng)怎么調(diào)整是刪除還是修改成數(shù)據(jù)頁的改動(dòng)這里下面的圖是按照自己的想法描述出來,如有誤望留言指正。
8.3.3 數(shù)據(jù)刷盤過程
數(shù)據(jù)刷盤flush的有四種情況
- InnoDB 的 redo log 寫滿了。這時(shí)候系統(tǒng)會(huì)停止所有更新操作,把 checkpoint 往前推進(jìn),redo log 留出空間可以繼續(xù)寫
- 系統(tǒng)內(nèi)存不足。當(dāng)需要新的內(nèi)存頁,而內(nèi)存不夠用的時(shí)候,就要淘汰一些數(shù)據(jù)頁,空出內(nèi)存給別的數(shù)據(jù)頁使用。如果淘汰的是“臟頁”,就要先將臟頁寫到磁盤
- MySQL 認(rèn)為系統(tǒng)“空閑”的時(shí)候
- MySQL 正常關(guān)閉的情況
數(shù)據(jù)刷盤也代表著Redo log檢查點(diǎn)checkpoint觸發(fā),這一步將聯(lián)系到第六章6.7和6.8中的章節(jié)內(nèi)容,較為復(fù)雜。
假設(shè)數(shù)據(jù)刷盤flush的四種情況發(fā)生了一種,那么聯(lián)系上文的過程將如下
- 將臟頁從內(nèi)存中刷回到數(shù)據(jù)磁盤
- 刷完后更新檢查點(diǎn)checkpoint的值
流程中間某個(gè)環(huán)節(jié)數(shù)據(jù)庫宕機(jī)后,恢復(fù)具體過程,這些留在心里了,沒往上去寫,讀者可以自行思考,不難。
九、結(jié)尾
整個(gè)文章講了Binlog、Undo log和Redo log,隨帶一提ChangeBuffer,前面四五六七章是分講,最后第八章是對(duì)整個(gè)日記相關(guān)聯(lián)講解。對(duì)此,講到這里,基本上要把我要講的已經(jīng)講完,內(nèi)容挺多,有耐心可以慢慢啃,不懂歡迎留言!
思考環(huán)節(jié),下面留下兩個(gè)問題,歡迎大家留言解答
1、為啥Binlog沒有crash-safe功能?
2、保證crash-safe為啥要用兩個(gè)日記,不能用一個(gè)日記嗎(Redo log或Binglog)?
作者: 神韻_499
原文鏈接:https://blog.csdn.net/qq_41055045/article/details/108681970