日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長(zhǎng)提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請(qǐng)做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會(huì)員:747

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

一、寫(xiě)作背景

大家都清楚,日志是 MySQL數(shù)據(jù)庫(kù)的重要組成部分,記錄著數(shù)據(jù)庫(kù)運(yùn)行期間各種狀態(tài)信息。MySQL日志主要包括錯(cuò)誤日志查詢?nèi)罩?/strong>、慢查詢?nèi)罩?/strong>、二進(jìn)制日志(binlog)事務(wù)日志(redo log、undo log)幾大類。

其中,二進(jìn)制日記事務(wù)日記尤為重要,一直被人重視、深入研究;可是事實(shí)很殘忍,重視或者說(shuō)大多數(shù)人一般都是了解個(gè)表面,真正懂得人并不多。真想攻破這兩塊日記必須下血本,而且還不一定能攻破。但是不要緊,為了讓你們省下血本還能順利攻破這兩塊日記,我連續(xù)研究幾周MySQL日記,最終肝出了這篇文章

二、文章指引

文章指導(dǎo):文章第三節(jié)內(nèi)容切莫跳過(guò)但如果覺(jué)得第四、第五、第六和第七節(jié)沒(méi)意思或者已經(jīng)有了概念,直接進(jìn)入文章第八節(jié)一舉攻破拿下。

文章方向:理論、原理篇。

三、必要概念字典介紹

基礎(chǔ)不牢地動(dòng)山搖,還是常規(guī)套路,先把必要知識(shí)普及/溫習(xí)一遍,當(dāng)后續(xù)文章出現(xiàn)疑慮反過(guò)來(lái)看下這些概念字典,說(shuō)不定能 “柳暗花明又一村” 呢?

寫(xiě)了又寫(xiě),想了又想,糾結(jié)了好久,這部分知識(shí)確實(shí)有點(diǎn)多,最后還是決定將這些必要概念字典單獨(dú)分出一個(gè)文章,后續(xù)打算用截圖方式引入各個(gè)章節(jié)中,建議遇到不懂名詞查閱一下字典。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖1:進(jìn)階知識(shí)部分示意圖

四、認(rèn)識(shí)二進(jìn)制日記(Binlog)

4.1 Binlog概念

Binlog 是邏輯日記,用于記錄數(shù)據(jù)庫(kù)執(zhí)行的寫(xiě)入操作(查詢不記錄)信息,Server層記錄和引擎層無(wú)關(guān),并且是以追加方式進(jìn)行寫(xiě)入,可以通過(guò)參數(shù) max_binlog_size 設(shè)置每個(gè)Binlog文件的大小,文件大小達(dá)到設(shè)定值時(shí)會(huì)生成新的文件來(lái)保存日記。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 


幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

4.2 Binlog 作用

在實(shí)際應(yīng)用中,主要用在兩個(gè)場(chǎng)景:主從復(fù)制和數(shù)據(jù)恢復(fù)

  • 主從復(fù)制場(chǎng)景:在Master主端開(kāi)啟Binlog,將Binlog發(fā)生到各個(gè)Slave從端,Slave從端重放Binlog從而達(dá)到主從數(shù)據(jù)一致
  • 數(shù)據(jù)恢復(fù)場(chǎng)景:通過(guò)使用 mysqlbinlog 工具來(lái)恢復(fù)數(shù)據(jù)

4.3 Binlog 記錄過(guò)程及刷盤(pán)時(shí)機(jī)

Binlog何時(shí)記錄將在第六點(diǎn)進(jìn)行介紹,大致記錄過(guò)程是先寫(xiě)B(tài)inlog Buffer,然后通過(guò)刷盤(pán)時(shí)機(jī),控制刷入OS Buffer,控制fsync()進(jìn)行寫(xiě)入Binlog File日記磁盤(pán)的過(guò)程。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

對(duì)于Binlog,MySQL是通過(guò)參數(shù)sync_binlog參數(shù)來(lái)控制刷盤(pán)時(shí)機(jī),取值是0、1和N三種值。0表示由系統(tǒng)自行判斷何時(shí)調(diào)用sync()寫(xiě)入磁盤(pán);1表示每次事務(wù)commit都要調(diào)用fsync()寫(xiě)入磁盤(pán);N表示每N個(gè)事務(wù),才會(huì)調(diào)用fsync()寫(xiě)入磁盤(pán)。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖2:內(nèi)存和磁盤(pán)日記結(jié)構(gòu)圖

4.4 Binlog 記錄格式

MySQL5.7.7版本之前默認(rèn)格式是STATEMENT,版本之后默認(rèn)是ROW,可以通過(guò)參數(shù) binlog-format指定。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

五、認(rèn)識(shí)事務(wù)日記(Undo log)

5.1 Undo log 概念

Undo log是邏輯日記、回滾日記。比如一條修改+3的邏輯語(yǔ)句,Undo log會(huì)記錄對(duì)應(yīng)一條-3的邏輯日記,一條插入語(yǔ)句則會(huì)記錄一條刪除語(yǔ)句,這樣發(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一致性視圖:通過(guò)Undo log找到對(duì)應(yīng)的數(shù)據(jù)版本號(hào),是保證MVCC視圖的一致性的必要條件。

5.3 Undo log 記錄過(guò)程及刷盤(pán)時(shí)機(jī)

刷盤(pán)過(guò)程及時(shí)機(jī)類似于Binlog和Redo,可以參考Redo log刷盤(pán)時(shí)機(jī)章節(jié)給出的圖片,已經(jīng)體現(xiàn)出來(lái)了。

5.4 Undo log 總結(jié)

Undo log日記內(nèi)容不是很多,重點(diǎn)是回滾多版本控制MVCC那塊。此外,我記得印象筆記深刻的是長(zhǎng)事務(wù)會(huì)導(dǎo)致日記過(guò)多,這個(gè)日記就是Undo log。因?yàn)殚L(zhǎng)事務(wù)存在,導(dǎo)致需要保存很多視圖快照,其實(shí)這里就是涉及到Undo log何時(shí)刪除和生成的問(wèn)題,當(dāng)時(shí)糾結(jié)好久,其實(shí)很簡(jiǎn)單。生成是事務(wù)開(kāi)始后寫(xiě)Redo log之前生成,當(dāng)沒(méi)有事務(wù)需要用到Undo log時(shí)就會(huì)被刪除。舉個(gè)例子,如果事務(wù)A一直存活,那么事務(wù)A之后產(chǎn)生的事務(wù)B、C...等等就算提交了,也不會(huì)被刪除,因?yàn)槭聞?wù)A需要用到B、C...事務(wù)去找A的版本。所以避免長(zhǎng)事務(wù)可以減少Undo log日記量,當(dāng)然還可以提高性能。

六、認(rèn)識(shí)事務(wù)日記 (Redo log)

6.1 Redo log 概念

Redo log 是重做日記,屬于InnoDB引擎的日記。是物理日記,日記記錄的內(nèi)容的是數(shù)據(jù)頁(yè)的更改,這個(gè)頁(yè) “做了什么改動(dòng)”。如:add xx記錄 to Page1,向數(shù)據(jù)頁(yè)P(yáng)age1增加一個(gè)記錄。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

6.2 Redo log 作用

  • 前滾操作:具備crash-safe能力,提供斷電重啟時(shí)解決事務(wù)丟失數(shù)據(jù)問(wèn)題。
  • 提高性能:先寫(xiě)Redo log記錄更新。當(dāng)?shù)鹊接锌臻e線程、內(nèi)存不足、Redo log滿了時(shí) “刷臟”。寫(xiě)Redo log是順序?qū)懭?,刷臟是隨機(jī)寫(xiě),節(jié)省的是隨機(jī)寫(xiě)磁盤(pán)的 IO 消耗(轉(zhuǎn)成順序?qū)懀?/strong>所以性能得到提升。此技術(shù)稱為WAL技術(shù):Write-Ahead Logging,它的關(guān)鍵點(diǎn)就是先寫(xiě)日記磁盤(pán),再寫(xiě)數(shù)據(jù)磁盤(pán)。

6.3 Redo log 的兩階段提交

更新內(nèi)存后引擎層寫(xiě)Redo log將狀態(tài)改成prepare為預(yù)提交第一階段,Server層寫(xiě)B(tài)inlog,將狀態(tài)改成commit為提交第二階段。兩階段提交可以確保Binlog和Redo log數(shù)據(jù)一致性。

6.4 Redo log 容災(zāi)恢復(fù)過(guò)程

MySQL的處理過(guò)程如下

  • 判斷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 刷盤(pán)時(shí)機(jī)

Undo log的刷盤(pán)時(shí)機(jī)和Redo log差不多,但是對(duì)于Undo log我沒(méi)找到對(duì)應(yīng)的刷盤(pán)參數(shù)設(shè)計(jì),所以不再提。Redo log每次先寫(xiě)入Redo Log Buffer中,然后通過(guò)刷盤(pán)時(shí)機(jī)控制刷入OS Buffer時(shí)間和刷入日記磁盤(pán)的時(shí)間。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖3:內(nèi)存和磁盤(pán)日記結(jié)構(gòu)圖

在Undo Log中,MySQL是通過(guò)參數(shù)innodb_flush_log_at_trx_commit來(lái)控制刷盤(pán)時(shí)機(jī),取值是0、1和2三種值。0表示事務(wù)提交后,每秒寫(xiě)入OS Buffer并調(diào)用fsync()寫(xiě)入日記磁盤(pán)中;1表示每次事務(wù)提交會(huì)寫(xiě)入OS Buffer并調(diào)用fsync()將日記寫(xiě)入日記磁盤(pán)中。2表示事務(wù)每次提交寫(xiě)入到OS Buffer,每秒調(diào)用fsync()寫(xiě)入日記磁盤(pán)。可見(jiàn)參數(shù)為1是最安全的,同時(shí)也是默認(rèn)值。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖4:Redo log刷盤(pán)時(shí)機(jī)參數(shù)對(duì)應(yīng)操作圖

6.6 Redo log 存儲(chǔ)方式

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖5:Redo log File環(huán)形存儲(chǔ)結(jié)構(gòu)圖

上圖是日記磁盤(pán)的Redo log環(huán)形設(shè)計(jì)圖(從頭寫(xiě),寫(xiě)到結(jié)束又從頭開(kāi)始寫(xiě)~循環(huán))。write pos和check point是兩個(gè)指針,write pos指針指向當(dāng)前日記文件寫(xiě)入的位置,check point指針指向當(dāng)前要擦除的開(kāi)始位置。圖中綠色部分是可以寫(xiě)入Redo log地方,每次寫(xiě)入,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è)過(guò)程就是需要進(jìn)行刷日記和數(shù)據(jù)磁盤(pán),記錄相應(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ù)庫(kù)會(huì)觸發(fā)檢查點(diǎn)checkpoint

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖6:檢查點(diǎn)觸發(fā)時(shí)機(jī)

Checkpoint發(fā)生的時(shí)間、條件及臟頁(yè)的選擇等都非常復(fù)雜。而Checkpoint所做的事情無(wú)外乎是將緩沖池中的臟頁(yè)刷回到磁盤(pán),不同之處在于每次刷新多少頁(yè)到磁盤(pán),每次從哪里取臟頁(yè),以及什么時(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ì)隨著日志的寫(xiě)入而逐漸增大。可以簡(jiǎn)單理解SLN就是記錄從開(kāi)始到現(xiàn)在已經(jīng)產(chǎn)生了多少字節(jié)的Redo log值。

存儲(chǔ)方式兩個(gè)指針又是通過(guò)LSN計(jì)算得到指向位置,因?yàn)長(zhǎng)SN記錄的是文件的大小字節(jié),當(dāng)超過(guò)文件大小時(shí),需要用取模計(jì)算出這兩個(gè)指針位置,取模使得寫(xiě)入就會(huì)從頭開(kāi)始寫(xiě),這樣使得兩個(gè)指針在一個(gè)文件中,一直落在循環(huán)位置,你追我趕的過(guò)程。這就是Redo log 環(huán)形邏輯思想設(shè)計(jì)實(shí)現(xiàn)。

上面提到LSN比較復(fù)雜,是因?yàn)樗泻芏鄠€(gè)值,輸入命令"show engine innodb status;",可以看到四個(gè)的lsn記錄

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖7:LSN值列表

為了方便識(shí)別,我都為它們重新命名,如下。名詞記不住,后面無(wú)法繼續(xù)深入

  1. 內(nèi)存日記:redo log buffer lsn;磁盤(pán)日記:redo log file lsn;

一般關(guān)系為:redo log buffer lsn >= redo log file lsn,如果刷盤(pán)時(shí)機(jī)為1,則redo log buffer lsn = redo log file lsn。

  1. 內(nèi)存數(shù)據(jù)頁(yè):data buffer lsn;數(shù)據(jù)磁盤(pán)數(shù)據(jù)頁(yè):data disk lsn;

一般關(guān)系為data buffer lsn > data disk lsn,如果已經(jīng)刷入數(shù)據(jù)磁盤(pán),則data buffer lsn = data disk lsn。

  1. 檢查點(diǎn):chckpoint lsn;

后面提到檢查點(diǎn)刷盤(pán),數(shù)據(jù)刷盤(pán)和日記刷盤(pán)(如果有日記刷盤(pán):則說(shuō)明我假設(shè)的日記刷盤(pán)的時(shí)機(jī)設(shè)置值不為1,為1是同步的,即始終redo log buffer lsn = redo log file lsn,不會(huì)由檢查點(diǎn)觸發(fā)刷日記磁盤(pán))。

都說(shuō)Redo log是環(huán)形記錄,那么怎么記錄的?下面結(jié)合LSN給出記錄過(guò)程虛構(gòu)圖,可以對(duì)比6.6 Redo log 存儲(chǔ)方式圖
相關(guān)知識(shí):日記磁盤(pán) + redo log file lsn + checkpoint lsn + 雙指針(write pos、check point)

1-8按時(shí)間順序發(fā)生。1點(diǎn)是假設(shè)最初的狀態(tài);2、3點(diǎn)寫(xiě)日記磁盤(pán);4點(diǎn)是觸發(fā)了檢查點(diǎn)checkpoint,進(jìn)行刷盤(pán),checkpoint lsn=1開(kāi)始,刷盤(pán)結(jié)束并更新checkpoint lsn=512。在5點(diǎn)、6點(diǎn)已經(jīng)刷過(guò)了一循環(huán)內(nèi)存、二循環(huán)內(nèi)存,從頭開(kāi)始寫(xiě)入log,兩個(gè)指針指向回到了頭部。第7點(diǎn)也是一個(gè)觸發(fā)checkpoint的過(guò)程。9點(diǎn)是假設(shè)沒(méi)有更新,最后達(dá)到平衡的結(jié)果,即內(nèi)存中數(shù)據(jù)頁(yè)和日記都完成了刷盤(pán)。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

圖8:Redo Log File存儲(chǔ)過(guò)程

整個(gè)流程:

在某些情況下,觸發(fā)checkpoint,觸發(fā)數(shù)據(jù)頁(yè)和日志頁(yè)刷盤(pán),此時(shí)將內(nèi)存中的臟數(shù)據(jù)---"數(shù)據(jù)臟頁(yè)"和"日志臟數(shù)據(jù)" 分別刷到數(shù)據(jù)磁盤(pán)和日記磁盤(pán)中,而且兩者刷盤(pán)速度不一樣。checkpoint會(huì)保護(hù)機(jī)制,當(dāng)數(shù)據(jù)刷盤(pán)速度超過(guò)日志刷盤(pán)時(shí),將會(huì)暫時(shí)停止數(shù)據(jù)刷盤(pán),等待日志刷盤(pán)進(jìn)度超過(guò)數(shù)據(jù)刷盤(pán)。

刷盤(pán)時(shí),對(duì)于數(shù)據(jù)磁盤(pán),全部都是在內(nèi)存中,此時(shí)每次刷一個(gè)數(shù)據(jù)頁(yè)到內(nèi)存更新數(shù)據(jù)頁(yè)也更新了data disk lsndata buffer lsn(在更新內(nèi)存數(shù)據(jù)頁(yè)時(shí),會(huì)更新data buffer lsn)。

對(duì)于日記磁盤(pán),除了要記錄checkpoint lsn的值為檢查點(diǎn) checkpoint的值(必須在結(jié)束時(shí) 直接記錄一個(gè)值,速度很快),這里是針對(duì)日記刷盤(pán)時(shí)機(jī)不是1(1是同步緩存刷日記刷盤(pán))時(shí),并且日記還沒(méi)刷到日記磁盤(pán)需要觸發(fā)將緩存中日記提前刷到日記磁盤(pán)中,此時(shí)會(huì)將redo buffer log刷到redo log file中也更新了redo log file lsnredo log buffer lsn 。

模擬檢查點(diǎn)觸發(fā)前后,整個(gè)流程變化,一個(gè)數(shù)據(jù)頁(yè)和日記,數(shù)據(jù)變化及l(fā)sn從179-180的變化圖(刷盤(pán)時(shí)機(jī)不為1)

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

6.9 Redo log 容災(zāi)恢復(fù)過(guò)程與LSN

結(jié)合6.4 Redo log 容災(zāi)恢復(fù)過(guò)程和6.8的LSN知識(shí),再次細(xì)化6.4的Redo log恢復(fù)過(guò)程

重啟innodb時(shí),Redo log完不完整,采用6.4知識(shí)過(guò)程。用Redo log恢復(fù),啟動(dòng)數(shù)據(jù)庫(kù)時(shí),InnoDB會(huì)掃描數(shù)據(jù)磁盤(pán)的數(shù)據(jù)頁(yè)data disk lsn和日志磁盤(pán)中的checkpoint lsn。兩者相等則從checkpoint lsn點(diǎn)開(kāi)始恢復(fù),恢復(fù)過(guò)程是利用 redo log到buffer pool,直到checkpoint lsn等于redo log file lsn,則恢復(fù)完成。

如果checkpoint lsn 小于 data disk lsn,說(shuō)明在檢查點(diǎn)觸發(fā)后還沒(méi)結(jié)束刷盤(pán)時(shí)數(shù)據(jù)庫(kù)宕機(jī)了。因?yàn)閏heckpoint lsn最新值是在數(shù)據(jù)刷盤(pán)結(jié)束后才記錄的,檢查點(diǎn)之后有一部分?jǐn)?shù)據(jù)已經(jīng)刷入數(shù)據(jù)磁盤(pán),這個(gè)時(shí)候數(shù)據(jù)磁盤(pán)已經(jīng)寫(xiě)入部分的部分恢復(fù)將不會(huì)重做,直接跳到?jīng)]有恢復(fù)的lsn值開(kāi)始恢復(fù)。

七、了解 ChangeBuffer

7.1 為啥提到ChangeBuffer

為啥本文我會(huì)提到ChangeBuffer呢,其實(shí)很多時(shí)候會(huì)將ChangeBuffer和Redo log搞混,兩者都是巧用內(nèi)存,減少磁盤(pán)IO,為了不弄混我覺(jué)得有必要專門(mén)對(duì)這個(gè)進(jìn)行一個(gè)講解。

7.2 ChangeBuffer概念及作用

下面是我對(duì)ChangeBuffer的簡(jiǎn)單介紹

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

也就是說(shuō)對(duì)于更新的操作,如果用到了ChangeBuffer,更新的數(shù)據(jù)所在的數(shù)據(jù)頁(yè)如果不在內(nèi)存中,將不用去數(shù)據(jù)磁盤(pán)將數(shù)據(jù)頁(yè)讀到內(nèi)存,而是將這一次操作記錄在ChangeBuffer中,ChangeBuffer 主要節(jié)省的則是隨機(jī)讀磁盤(pán)的 IO 消耗,下次讀取查詢等讀取數(shù)據(jù)頁(yè)時(shí)用上ChangeBuffer中的記錄即可。其實(shí)也是一種巧用內(nèi)存的思想。

7.3 ChangeBuffer與Redo log區(qū)別

Redo log 主要節(jié)省的是隨機(jī)寫(xiě)磁盤(pán)的 IO 消耗(轉(zhuǎn)成順序?qū)懀?ChangeBuffer 主要節(jié)省的則是隨機(jī)讀磁盤(pán)的 IO 消耗。

這句話怎么理解,看下面:

Redo log 與 ChangeBuffer(含磁盤(pán)持久化) 這2個(gè)機(jī)制,不同之處在于優(yōu)化了整個(gè)變更流程的不同階段。

先不考慮Redo log、ChangeBuffer機(jī)制,簡(jiǎn)化抽象一個(gè)更新(insert、update、delete)流程:

  1. 從磁盤(pán)讀取待變更的行所在的數(shù)據(jù)頁(yè),讀入內(nèi)存頁(yè)中
  2. 對(duì)內(nèi)存頁(yè)中的行,執(zhí)行變更操作
  3. 將變更后的數(shù)據(jù)頁(yè),寫(xiě)入至數(shù)據(jù)磁盤(pán)中

其中,流程中的步驟1涉及隨機(jī)讀磁盤(pán)IO;步驟3涉及隨機(jī)寫(xiě)磁盤(pán)IO;剛好對(duì)應(yīng)ChangeBuffer和Redo log。

對(duì)那句話的理解答案:

  • ChangeBuffer機(jī)制,優(yōu)化了步驟1——避免了隨機(jī)讀磁盤(pán)IO ,將不在內(nèi)存中的數(shù)據(jù)頁(yè)的操作寫(xiě)入ChangeBuffer中,而不是將數(shù)據(jù)頁(yè)從磁盤(pán)讀入內(nèi)存頁(yè)中
  • Redo log機(jī)制, 優(yōu)化了步驟3——避免了隨機(jī)寫(xiě)磁盤(pán)IO,將隨機(jī)寫(xiě)磁盤(pán),優(yōu)化為了順序?qū)懘疟P(pán)(寫(xiě)Redo log,確保crash-safe)

7.4 有沒(méi)有用到ChangeBuffer對(duì)于Redo log的區(qū)別

Redo log機(jī)制,為了保證crash-safe,一直都會(huì)用到。 有無(wú)用到ChangeBuffer機(jī)制,對(duì)于redo log這步的區(qū)別在于—— 用到了ChangeBuffer機(jī)制時(shí),在Redo log中記錄的本次變更,是記錄new change buffer item相關(guān)的信息,而不是直接的記錄物理頁(yè)的變更(文章中第八節(jié)都有體現(xiàn)這一過(guò)程)。 在我們mysql innodb中, ChangeBuffer機(jī)制不是一直會(huì)被應(yīng)用到,僅當(dāng)待操作的數(shù)據(jù)頁(yè)當(dāng)前不在內(nèi)存中,需要先讀磁盤(pán)加載數(shù)據(jù)頁(yè)時(shí),ChangeBuffer才有用武之地。

7.5 ChangeBuffer的merge過(guò)程

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

除了訪問(wèn)這個(gè)數(shù)據(jù)也會(huì)觸發(fā) merge 外,系統(tǒng)有后臺(tái)線程會(huì)定期 merge。在數(shù)據(jù)庫(kù)正常關(guān)閉(shutdown)的過(guò)程中,也會(huì)執(zhí)行 merge 操作。

merge過(guò)程做三步

  1. 從磁盤(pán)讀入數(shù)據(jù)頁(yè)到內(nèi)存(老版本的數(shù)據(jù)頁(yè));
  2. 從 change buffer 里找出這個(gè)數(shù)據(jù)頁(yè)的 change buffer 記錄 (可能有多個(gè)),依次應(yīng)用,得到新版數(shù)據(jù)頁(yè);
  3. 寫(xiě) redo log。這個(gè) redo log 包含了數(shù)據(jù)的變更和 change buffer 的變更。

八、日記大連貫U-R-B,一舉攻破拿下

前面分別講的是Binlog、Undo log和Redo log,下面將他們都串聯(lián)起來(lái),在一些流程體現(xiàn)全部日記。

同樣,以一些最經(jīng)典的更新語(yǔ)句例子展開(kāi)說(shuō)明。

8.1 制造演示數(shù)據(jù)

測(cè)試語(yǔ)句:插入語(yǔ)句+查詢語(yǔ)句,a字段是普通索引

insert into ta(a,b) values(2,5),(7, 5)2、select * from t where a in (2, 7)

假設(shè)原來(lái)的數(shù)據(jù)如下圖,數(shù)據(jù)頁(yè)page1在內(nèi)存中,page2不在。插入的數(shù)據(jù)(2,5)落在page1,數(shù)據(jù)(7,5)落在page2中。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

8.2 假設(shè)沒(méi)有日記和ChangeBuffer 示范

先不考慮所有日記及ChangeBuffer機(jī)制,簡(jiǎn)化抽象一個(gè)更新insert流程

  1. 從磁盤(pán)讀取待變更的行所在的數(shù)據(jù)頁(yè),讀入內(nèi)存頁(yè)中
  2. 對(duì)內(nèi)存頁(yè)中的行,執(zhí)行變更操作
  3. 將變更后的數(shù)據(jù)頁(yè),寫(xiě)入至數(shù)據(jù)磁盤(pán)中
幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

8.3 考慮所有日記和ChangeBuffer 示范--現(xiàn)有Innodb流程

過(guò)程是 兩階段提交-----日記刷盤(pán)------數(shù)據(jù)刷盤(pán)(涉及Redo log lsn 和 ChangeBuffer的內(nèi)容)

8.3.1 兩階段提交過(guò)程

  1. 數(shù)據(jù)(2,5)所在頁(yè)page1在內(nèi)存中直接更新內(nèi)存;數(shù)據(jù)(7,5)所在頁(yè)page2不在內(nèi)存中,記錄change buffer(具有唯一性的索引或者沒(méi)有使用change buffer的操作是將磁盤(pán)中的數(shù)據(jù)頁(yè)讀入內(nèi)存中并做更新)。
  2. 寫(xiě)undo日記。先寫(xiě)緩存,后面根據(jù)刷盤(pán)參數(shù)決定何時(shí)刷入磁盤(pán),后面的redo/Binlog都一樣。日記刷盤(pán) 在每一個(gè)日記中基本已經(jīng)提到,它和設(shè)置的參數(shù)有關(guān),具體刷盤(pán)可以參考上文4.3和6.5章節(jié),下文不會(huì)再展開(kāi)介紹。
  3. 寫(xiě)redo日記(先記在內(nèi)存中的更新,然后記錄在內(nèi)存中的change buffer的改變)
  4. 日記狀態(tài)改成prepare階段。
  5. 寫(xiě)B(tài)inlog日記。
  6. 提交事務(wù),日記狀態(tài)改成commit階段。
幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

8.3.2 merge 過(guò)程

緊接著上文,圖片可上下參考,假設(shè)現(xiàn)在執(zhí)行查詢語(yǔ)句 “select * from t where a in (2, 7)” ,此次查詢索引a=7所在的數(shù)據(jù)頁(yè)不在內(nèi)存中,并且上一步更新已經(jīng)在change buffer中有記錄,將會(huì)觸發(fā)merge過(guò)程(參考第七章節(jié)7.5)。

  1. 將page2讀入內(nèi)存
  2. 依次應(yīng)用change buffer中的記錄,得到最新版數(shù)據(jù)頁(yè)
  3. 寫(xiě)入redo,之前記錄的changebuffer改動(dòng),現(xiàn)在改成數(shù)據(jù)頁(yè)的改動(dòng)

至于changebuffer被應(yīng)用后是刪除還是標(biāo)記,還有redo中原有的記錄changebuffer的改動(dòng)怎么調(diào)整是刪除還是修改成數(shù)據(jù)頁(yè)的改動(dòng)這里下面的圖是按照自己的想法描述出來(lái),如有誤望留言指正。

幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

8.3.3 數(shù)據(jù)刷盤(pán)過(guò)程

數(shù)據(jù)刷盤(pán)flush的有四種情況

  1. InnoDB 的 redo log 寫(xiě)滿了。這時(shí)候系統(tǒng)會(huì)停止所有更新操作,把 checkpoint 往前推進(jìn),redo log 留出空間可以繼續(xù)寫(xiě)
  2. 系統(tǒng)內(nèi)存不足。當(dāng)需要新的內(nèi)存頁(yè),而內(nèi)存不夠用的時(shí)候,就要淘汰一些數(shù)據(jù)頁(yè),空出內(nèi)存給別的數(shù)據(jù)頁(yè)使用。如果淘汰的是“臟頁(yè)”,就要先將臟頁(yè)寫(xiě)到磁盤(pán)
  3. MySQL 認(rèn)為系統(tǒng)“空閑”的時(shí)候
  4. MySQL 正常關(guān)閉的情況

數(shù)據(jù)刷盤(pán)也代表著Redo log檢查點(diǎn)checkpoint觸發(fā),這一步將聯(lián)系到第六章6.7和6.8中的章節(jié)內(nèi)容,較為復(fù)雜。

假設(shè)數(shù)據(jù)刷盤(pán)flush的四種情況發(fā)生了一種,那么聯(lián)系上文的過(guò)程將如下

  1. 將臟頁(yè)從內(nèi)存中刷回到數(shù)據(jù)磁盤(pán)
  2. 刷完后更新檢查點(diǎn)checkpoint的值
幾年了,作為一個(gè)碼農(nóng)終于把MySQL日記看懂了

 

流程中間某個(gè)環(huán)節(jié)數(shù)據(jù)庫(kù)宕機(jī)后,恢復(fù)具體過(guò)程,這些留在心里了,沒(méi)往上去寫(xiě),讀者可以自行思考,不難。

九、結(jié)尾

整個(gè)文章講了Binlog、Undo log和Redo log,隨帶一提ChangeBuffer,前面四五六七章是分講,最后第八章是對(duì)整個(gè)日記相關(guān)聯(lián)講解。對(duì)此,講到這里,基本上要把我要講的已經(jīng)講完,內(nèi)容挺多,有耐心可以慢慢啃,不懂歡迎留言!

思考環(huán)節(jié),下面留下兩個(gè)問(wèn)題,歡迎大家留言解答

1、為啥Binlog沒(méi)有crash-safe功能?

2、保證crash-safe為啥要用兩個(gè)日記,不能用一個(gè)日記嗎(Redo log或Binglog)?

作者: 神韻_499

原文鏈接:https://blog.csdn.net/qq_41055045/article/details/108681970

分享到:
標(biāo)簽:日記 MySQL
用戶無(wú)頭像

網(wǎng)友整理

注冊(cè)時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會(huì)員

趕快注冊(cè)賬號(hào),推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過(guò)答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫(kù),初中,高中,大學(xué)四六

運(yùn)動(dòng)步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動(dòng)步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績(jī)?cè)u(píng)定2018-06-03

通用課目體育訓(xùn)練成績(jī)?cè)u(píng)定