3000幀動畫圖解MySQL為什么需要binlog函喉、redo log和undo log

全文建立在MySQL的存儲引擎為InnoDB的基礎上

先看一條SQL如何入庫的:

這是一條很簡單的更新SQL,從MySQL服務端接收到SQL到落盤荣月,先后經(jīng)過了MySQL Server層和InnoDB存儲引擎管呵。

  1. Server層就像一個產(chǎn)品經(jīng)理,分析客戶的需求哺窄,并給出實現(xiàn)需求的方案捐下。
  2. InnoDB就像一個基層程序員,實現(xiàn)產(chǎn)品經(jīng)理給出的具體方案萌业。

在MySQL”分析需求坷襟,實現(xiàn)方案“的過程中,還夾雜著內(nèi)存操作和磁盤操作生年,以及記錄各種日志婴程。

他們到底有什么用處?他們之間到底怎么配合的抱婉?MySQL又為什么要分層呢档叔?InnoDB里面的那一塊Buffer Pool又是什么?

我們慢慢分析蒸绩。

分層結(jié)構(gòu)

MySQL為什么要分為Server層和存儲引擎兩層呢蹲蒲?

這個問題官方也沒有給出明確的答案,但是也不難猜侵贵,簡單來說就是為了“解耦”。

Server層和存儲引擎各司其職缘薛,分工明確窍育,用戶可以根據(jù)不同的需求去使用合適的存儲引擎卡睦,多好的設計,對不對漱抓?

后來的發(fā)展也驗證了“分層設計”的優(yōu)越性:MySQL最初搭載的存儲引擎是自研的只支持簡單查詢的MyISAM的前身ISAM表锻,后來與Sleepycat合作研發(fā)了Berkeley DB引擎,支持了事務乞娄。江山代有才人出瞬逊,技術(shù)后浪推前浪,MySQL在持續(xù)的升級著自己的存儲引擎的過程中仪或,遇到了橫空出世的InnoDB确镊,InnoDB的功能強大讓MySQL倍感壓力。

自己的存儲引擎打不過InnoDB怎么辦范删?

打不過就加入蕾域!


MySQL選擇了和InnoDB合作。正是因為MySQL存儲引擎的插件化設計到旦,兩個公司合作的非常順利旨巷,MySQL也在合作后不久就發(fā)布了正式支持nnoDB的4.0版本以及經(jīng)典的4.1版本。

MySQL兼并天下模式也成為MySQL走向繁榮的一個重要因素添忘。這能讓MySQL長久地保持著極強競爭力采呐。時至今日,MySQL依然占據(jù)著極高數(shù)據(jù)庫市場份額搁骑,僅次于王牌數(shù)據(jù)庫Oracle斧吐。

3.png

Buffer Pool

在InnoDB里,有一塊非常重要的結(jié)構(gòu)——Buffer Pool靶病。

4.png

Buffer Pool是個什么東西呢会通?

Buffer Pool就是一塊用于緩存MySQL磁盤數(shù)據(jù)的內(nèi)存空間。

為什么要緩存MySQL磁盤數(shù)據(jù)呢娄周?

我們通過一個例子說明涕侈,我們先假設沒有Buffer Pool,user表里面只有一條記錄煤辨,記錄的age = 1裳涛,假設需要執(zhí)行三條SQL:

  1. 事務A:update user set age = 2
  2. 事務B:update user set age = 3
  3. 事務C:update user set age = 4

如果沒有Buffer Pool,那執(zhí)行就是這樣的:

5.gif

從圖上可以看出众辨,每次更新都需要從磁盤拿數(shù)據(jù)(1次IO)端三,修改完了需要刷到磁盤(1次IO),也就是每次更新都需要2次磁盤IO鹃彻。三次更新需要6次磁盤IO郊闯。

而有了Buffer Pool,執(zhí)行就成了這樣:

6.gif

從圖上可以看出,只需要在第一次執(zhí)行的時候?qū)?shù)據(jù)從磁盤拿到Buffer Pool(1次IO)团赁,第三次執(zhí)行完將數(shù)據(jù)刷回磁盤(1次IO)育拨,整個過程只需要2次磁盤IO,比沒有Buffer Pool節(jié)省了4次磁盤IO的時間欢摄。

當然熬丧,Buffer Pool真正的運轉(zhuǎn)流程沒有這么簡單,具體實現(xiàn)細節(jié)和優(yōu)化技巧還有很多怀挠,由于篇幅有限析蝴,本文不做詳細描述。

我想表達的是:Buffer Pool就是將磁盤IO轉(zhuǎn)換成了內(nèi)存操作绿淋,節(jié)省了時間闷畸,提高了效率。

Buffer Pool是提高了效率沒錯躬它,但是出現(xiàn)了一個問題腾啥,Buffer Pool是基于內(nèi)存的,而只要一斷電冯吓,內(nèi)存里面的數(shù)據(jù)就會全部丟失倘待。

如果斷電的時候Buffer Pool的數(shù)據(jù)還沒來得及刷到磁盤,那么這些數(shù)據(jù)就丟失了嗎组贺?

還是上面的那個例子凸舵,如果三個事務執(zhí)行完畢,在age = 4還沒有刷到磁盤的時候失尖,突然斷電啊奄,數(shù)據(jù)就全部丟掉了:

7.gif

試想一下,如果這些丟失的數(shù)據(jù)是核心的用戶交易數(shù)據(jù)掀潮,那用戶能接受嗎菇夸?

答案是否定的。

那InnoDB是如何做到數(shù)據(jù)不會丟失的呢仪吧?

今天的第一個日志——redo log登場了庄新。

恢復 - redo log

顧名思義,redo是重做的意思薯鼠,redo log就是重做日志的意思择诈。

redo log是如何保證數(shù)據(jù)不會丟失的呢?

就是在修改之后出皇,先將修改后的值記錄到磁盤上的redo log中羞芍,就算突然斷電了,Buffer Pool中的數(shù)據(jù)全部丟失了郊艘,來電的時候也可以根據(jù)redo log恢復Buffer Pool荷科,這樣既利用到了Buffer Pool的內(nèi)存高效性唯咬,也保證了數(shù)據(jù)不會丟失。

我們通過一個例子說明,我們先假設沒有Buffer Pool,user表里面只有一條記錄信卡,記錄的age = 1娶聘,假設需要執(zhí)行一條SQL:

  1. 事務A:update user set age = 2

執(zhí)行過程如下:

8.gif

如上圖,有了redo log之后斥滤,將age修改成2之后将鸵,馬上將age = 2寫到redo log里面,如果這個時候突然斷電內(nèi)存數(shù)據(jù)丟失佑颇,在來電的時候顶掉,可以將redo log里面的數(shù)據(jù)讀出來恢復數(shù)據(jù),用這樣的方式保證了數(shù)據(jù)不會丟失挑胸。

你可能會問痒筒,redo log文件也在磁盤上,數(shù)據(jù)文件也在磁盤上茬贵,都是磁盤操作簿透,何必多此一舉?為什么不直接將修改的數(shù)據(jù)寫到數(shù)據(jù)文件里面去呢解藻?

傻瓜老充,因為redo log是磁盤順序?qū)懀瑪?shù)據(jù)刷盤是磁盤隨機寫螟左,磁盤的順序?qū)懕入S機寫高效的多啊啡浊。

這種先預寫日志后面再將數(shù)據(jù)刷盤的機制,有一個高大上的專業(yè)名詞——WAL(Write-ahead logging)胶背,翻譯成中文就是預寫式日志巷嚣。

雖然磁盤順序?qū)懸呀?jīng)很高效了,但是和內(nèi)存操作還是有一定的差距钳吟。

那么廷粒,有沒有辦法進一步優(yōu)化一下呢?

答案是可以砸抛。那就是給redo log也加一個內(nèi)存buffer评雌,也就是redo log buffer,用這種套娃式的方法進一步提高效率直焙。


10.png

redo log buffer具體是怎么配合刷盤呢景东?

在這個問題之前之前,我們先來捋一下MySQL服務端和操作系統(tǒng)的關(guān)系:

MySQL服務端是一個進程奔誓,它運行于操作系統(tǒng)之上斤吐。也就是說搔涝,操作系統(tǒng)掛了MySQL一定掛了,但是MySQL掛了操作系統(tǒng)不一定掛和措。

所以MySQL掛了有兩種情況:

  1. MySQL掛了庄呈,操作系統(tǒng)也掛了,也就是常說的服務器宕機了派阱。這種情況Buffer Pool里面的數(shù)據(jù)會全部丟失诬留,操作系統(tǒng)的os cache里面的數(shù)據(jù)也會丟失。
  2. MySQL掛了贫母,操作系統(tǒng)沒有掛文兑。這種情況Buffer Pool里面的數(shù)據(jù)會全部丟失,操作系統(tǒng)的os cache里面的數(shù)據(jù)不會丟失腺劣。

OK绿贞,了解了MySQL服務端和操作系統(tǒng)的關(guān)系之后,再來看redo log的落盤機制橘原。redo log的刷盤機制由參數(shù)innodb_flush_log_at_trx_commit控制籍铁,這個參數(shù)有3個值可以設置:

  1. innodb_flush_log_at_trx_commit = 1:實時寫,實時刷
  2. innodb_flush_log_at_trx_commit = 0:延遲寫趾断,延遲刷
  3. innodb_flush_log_at_trx_commit = 2:實時寫拒名,延遲刷

寫可以理解成寫到操作系統(tǒng)的緩存(os cache),刷可以理解成把操作系統(tǒng)里面的緩存刷到磁盤歼冰。

這三種策略的區(qū)別靡狞,我們分開討論:

innodb_flush_log_at_trx_commit = 1:實時寫,實時刷

這種策略會在每次事務提交之前隔嫡,每次都會將數(shù)據(jù)從redo log刷到磁盤中去甸怕,理論上只要磁盤不出問題,數(shù)據(jù)就不會丟失腮恩。

總結(jié)來說梢杭,這種策略效率最低,但是丟數(shù)據(jù)風險也最低秸滴。

11.gif

innodb_flush_log_at_trx_commit = 0:延遲寫武契,延遲刷

這種策略在事務提交時,只會把數(shù)據(jù)寫到redo log buffer中荡含,然后讓后臺線程定時去將redo log buffer里面的數(shù)據(jù)刷到磁盤咒唆。

這種策略是最高效的,但是我們都知道释液,定時任務是有間隙的全释,但是如果事務提交后,后臺線程沒來得及將redo log刷到磁盤误债,這個時候不管是MySQL進程掛了還是操作系統(tǒng)掛了浸船,這一部分數(shù)據(jù)都會丟失妄迁。

總結(jié)來說這種策略效率最高,丟數(shù)據(jù)的風險也最高李命。

12.gif

innodb_flush_log_at_trx_commit = 2:實時寫登淘,延遲刷

這種策略在事務提交之前會把redo log寫到os cache中,但并不會實時地將redo log刷到磁盤封字,而是會每秒執(zhí)行一次刷新磁盤操作黔州。

這種情況下如果MySQL進程掛了,操作系統(tǒng)沒掛的話阔籽,操作系統(tǒng)還是會將os cache刷到磁盤辩撑,數(shù)據(jù)不會丟失,如下圖:

13.gif

但如果MySQL所在的服務器掛掉了仿耽,也就是操作系統(tǒng)都掛了,那么os cache也會被清空各薇,數(shù)據(jù)還是會丟失项贺。如下圖:

14.gif

所以,這種redo log刷盤策略是上面兩種策略的折中策略峭判,效率比較高开缎,丟失數(shù)據(jù)的風險比較低,絕大多情況下都推薦這種策略林螃。

總結(jié)一下奕删,redo log的作用是用于恢復數(shù)據(jù),寫redo log的過程是磁盤順序?qū)懥迫希腥N刷盤策略完残,有innodb_flush_log_at_trx_commit 參數(shù)控制,推薦設置成2横漏。

回滾 - undo log

我們都知道谨设,InnoDB是支持事務的,而事務是可以回滾的缎浇。

假如一個事務將age=1修改成了age=2扎拣,在事務還沒有提交的時候,后臺線程已經(jīng)將age=2刷入了磁盤素跺。這個時候二蓝,不管是內(nèi)存還是磁盤上,age都變成了2指厌,如果事務要回滾刊愚,找不到修改之前的age=1,無法回滾了仑乌。

15.gif

那怎么辦呢百拓?

很簡單琴锭,把修改之前的age=1存起來,回滾的時候根據(jù)存起來的age=1回滾就行了衙传。

MySQL確實是這么干的决帖!這個記錄修改之前的數(shù)據(jù)的過程,叫做記錄undo log蓖捶。undo翻譯成中文是撤銷地回、回滾的意思,undo log的主要作用也就是回滾數(shù)據(jù)俊鱼。

如何回滾呢刻像?看下面這個圖:

16.gif

MySQL在將age = 1修改成age = 2之前,先將age = 1存到undo log里面去并闲,這樣需要回滾的時候细睡,可以將undo log里面的age = 1讀出來回滾。

需要注意的是帝火,undo log默認存在全局表空間里面溜徙,你可以簡單的理解成undo log也是記錄在一個MySQL的表里面,插入一條undo log和插入一條普通數(shù)據(jù)是類似犀填。也就是說蠢壹,寫undo log的過程中同樣也是要寫入redo log的。

歸檔 - binlog

undo log記錄的是修改之前的數(shù)據(jù)九巡,提供回滾的能力图贸。

redo log記錄的是修改之后的數(shù)據(jù),提供了崩潰恢復的能力冕广。

那binlog是干什么的呢疏日?

binlog記錄的是修改之后的數(shù)據(jù),用于歸檔佳窑。

和redo log日志類似制恍,binlog也有著自己的刷盤策略,通過sync_binlog參數(shù)控制:

  • sync_binlog = 0 :每次提交事務前將binlog寫入os cache神凑,由操作系統(tǒng)控制什么時候刷到磁盤
  • sync_binlog =1 :采用同步寫磁盤的方式來寫binlog净神,不使用os cache來寫binlog
  • sync_binlog = N :當每進行n次事務提交之后,調(diào)用一次fsync將os cache中的binlog強制刷到磁盤

那么問題來了溉委,binlog和redo log都是記錄的修改之后的值鹃唯,這兩者有什么區(qū)別呢?有redo log為什么還需要binlog呢瓣喊?

首先看兩者的一些區(qū)別:

  • binlog是邏輯日志坡慌,記錄的是對哪一個表的哪一行做了什么修改;redo log是物理日志藻三,記錄的是對哪個數(shù)據(jù)頁中的哪個記錄做了什么修改洪橘,如果你還不了解數(shù)據(jù)頁跪者,你可以理解成對磁盤上的哪個數(shù)據(jù)做了修改。
  • binlog是追加寫熄求;redo log是循環(huán)寫渣玲,日志文件有固定大小,會覆蓋之前的數(shù)據(jù)弟晚。
  • binlog是Server層的日志忘衍;redo log是InnoDB的日志。如果不使用InnoDB引擎卿城,是沒有redo log的枚钓。

但說實話,我覺得這些區(qū)別并不是redo log不能取代binlog的原因瑟押,MySQL官方完全可以調(diào)整redo log讓他兼并binlog的能力搀捷,但他沒有這么做,為什么呢多望?

我認為不用redo log取代binlog最大的原因是“沒必要”指煎。

為什么這么說呢?

第一點便斥,binlog的生態(tài)已經(jīng)建立起來。MySQL高可用主要就是依賴binlog復制威始,還有很多公司的數(shù)據(jù)分析系統(tǒng)和數(shù)據(jù)處理系統(tǒng)枢纠,也都是依賴的binlog。取代binlog去改變一個生態(tài)費力了不討好黎棠。

第二點晋渺,binlog并不是MySQL的瓶頸,花時間在沒有瓶頸的地方?jīng)]必要脓斩。

總結(jié)

總結(jié)一下:

  1. Buffer Pool是MySQL進程管理的一塊內(nèi)存空間木西,有減少磁盤IO次數(shù)的作用。
  2. redo log是InnoDB存儲引擎的一種日志随静,主要作用是崩潰恢復八千,有三種刷盤策略,有innodb_flush_log_at_trx_commit 參數(shù)控制燎猛,推薦設置成2恋捆。
  3. undo log是InnoDB存儲引擎的一種日志,主要作用是回滾重绷。
  4. binlog是MySQL Server層的一種日志沸停,主要作用是歸檔。
  5. MySQL掛了有兩種情況:操作系統(tǒng)掛了MySQL進程跟著掛了昭卓;操作系統(tǒng)沒掛愤钾,但是MySQL進程掛了瘟滨。

最后,再用一張圖總結(jié)一下全文的知識點:

17.png

寫在最后

這篇文章寫在一年之前能颁,本來覺得是一篇水文沒想要發(fā)杂瘸,最近無聊修改了一下發(fā)了出來,希望能夠用動圖的形式幫助到MySQL基礎不太好的朋友劲装,大神忽略就好胧沫。

需要強調(diào)的一點是,由于作者水平有限占业,本文只是淺顯的從無到有地闡述了MySQL幾種日志的大致作用绒怨,過程中省略了很多細節(jié),比如Buffer Pool的實現(xiàn)細節(jié)谦疾,比如undo log和MVCC的關(guān)系南蹂,比如binlog buffer、change buffer的存在念恍,比如redo log的兩階段提交六剥。

如果您有任何問題,我們可以探討峰伙,如果您在文中發(fā)現(xiàn)錯誤疗疟,還望您指出,萬分感謝瞳氓!

好了策彤,今天的文章就到這里了。

感謝你的閱讀匣摘!我是CoderW店诗,我們下期再見。

最后音榜,歡迎關(guān)注我的公眾號“CoderW”一起探討進步~~~~

參考資料

  • 《MySQL實戰(zhàn)45講》
  • 《從根兒上理解MySQL》
  • 《MySQL技術(shù)內(nèi)幕—InnoDB存儲引擎》第2版
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末庞瘸,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子赠叼,更是在濱河造成了極大的恐慌擦囊,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件嘴办,死亡現(xiàn)場離奇詭異霜第,居然都是意外死亡,警方通過查閱死者的電腦和手機户辞,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進店門泌类,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事刃榨〉猓” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵枢希,是天一觀的道長桌吃。 經(jīng)常有香客問我,道長苞轿,這世上最難降的妖魔是什么茅诱? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮搬卒,結(jié)果婚禮上瑟俭,老公的妹妹穿的比我還像新娘。我一直安慰自己契邀,他們只是感情好摆寄,可當我...
    茶點故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著坯门,像睡著了一般微饥。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上古戴,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天欠橘,我揣著相機與錄音,去河邊找鬼现恼。 笑死简软,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的述暂。 我是一名探鬼主播,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼建炫,長吁一口氣:“原來是場噩夢啊……” “哼畦韭!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起肛跌,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤艺配,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后衍慎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體转唉,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年稳捆,在試婚紗的時候發(fā)現(xiàn)自己被綠了赠法。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡乔夯,死狀恐怖砖织,靈堂內(nèi)的尸體忽然破棺而出款侵,到底是詐尸還是另有隱情,我是刑警寧澤侧纯,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布新锈,位于F島的核電站,受9級特大地震影響眶熬,放射性物質(zhì)發(fā)生泄漏妹笆。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一娜氏、第九天 我趴在偏房一處隱蔽的房頂上張望拳缠。 院中可真熱鬧,春花似錦牍白、人聲如沸脊凰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽狸涌。三九已至,卻和暖如春最岗,著一層夾襖步出監(jiān)牢的瞬間帕胆,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工般渡, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留懒豹,地道東北人。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓驯用,卻偏偏與公主長得像脸秽,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蝴乔,可洞房花燭夜當晚...
    茶點故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容