mysql的斷電恢復(fù)能力

概述

這段時(shí)間對(duì)mysql數(shù)據(jù)庫(kù)事務(wù)的acid做了一些深入的研究囱皿,理解了如何在異常情況下保證事務(wù)的acid氏堤。而最嚴(yán)重的異常情況莫過于斷電必盖,隨時(shí)都有可能發(fā)生且發(fā)生時(shí)不會(huì)有任何保存的機(jī)會(huì)赞咙,所以就想以事務(wù)處理的各個(gè)階段發(fā)生斷電的情況下mysql如何保證acid為切入點(diǎn)總結(jié)一下這段時(shí)間所學(xué)到的東西普监。
本文將重點(diǎn)介紹commit命令執(zhí)行的各個(gè)階段贵试,mysql是如何進(jìn)行斷電恢復(fù)的。

mysql的page凯正、日志和buffer介紹

page

mysql的page與文件系統(tǒng)的block類似毙玻,是mysql自己定義的讀取和寫入磁盤的最小單位,其目的是為了充分的利用磁盤的順序訪問速度快的優(yōu)勢(shì)廊散。一般是磁盤扇區(qū)的4~16倍桑滩。

logs

  • undolog。即 mvcc 歷史快照允睹,記錄的是某行過去的某個(gè)版本运准,用于幫助事務(wù)回滾及 MVCC 的功能。存儲(chǔ)在表空間缭受,以 transaction 為維度記錄胁澳,且記錄了 transaction 狀態(tài) ,可用于 crash 恢復(fù)時(shí)提取未提交的事務(wù)米者【禄可以理解成一張?zhí)厥獾谋恚矔?huì)用到 buffer pool 蔓搞。
  • redolog胰丁。可以理解為內(nèi)存數(shù)據(jù)的WAL(write-ahead-log)喂分,用來恢復(fù)未flush到disk的page數(shù)據(jù)锦庸。記錄的是對(duì)頁的二進(jìn)制級(jí)別的修改操作,比如某個(gè)偏移寫入'aa'記錄蒲祈。** 一般存儲(chǔ)在單獨(dú)的redo log文件中甘萧,數(shù)據(jù)庫(kù)全局的。另外要注意的是讳嘱, undolog 的寫入也會(huì)生成對(duì)應(yīng)的 redo log 幔嗦。**
  • binlog。即我們常說的二進(jìn)制日志沥潭,主要用于主從復(fù)制。

buffer

  • buffer pool嬉挡。即 mysql page 的 buffer 钝鸽。使用 lru 來管理汇恤。
  • doublewrite buffer。在 flush page 到磁盤之前拔恰,會(huì)先將 page 寫入這里因谎,為了防止 page flush 到一半時(shí)斷電造成的磁盤 page 數(shù)據(jù)不完整的問題。存儲(chǔ)介質(zhì)雖為文件颜懊,但充分利用順序?qū)懖撇恚院芸臁?/li>
  • log buffer。即 redolog 的內(nèi)存 buffer 河爹。 用于降低 redolog 對(duì)于寫入速度的影響匠璧。

除了這些還有 change buffer 等,不影響接下來的內(nèi)容介紹咸这,故不在此處展開討論夷恍。

mysql寫入過程簡(jiǎn)介

commit 之前

先說說 commit 命令之前,寫入操作對(duì)應(yīng)的過程媳维。 此時(shí)所有的寫入操作都會(huì)通過 undolog 的支持酿雪,同時(shí)保留寫入之前的版本和寫入之后的版本,而這里對(duì)表數(shù)據(jù)和 undolog 的修改并不會(huì)直接寫入到磁盤中侄刽,而是寫入 buffer pool 中指黎,同時(shí)生成相應(yīng)的 redolog 。而此時(shí)的 redolog 存放在 log buffer 中州丹,這樣做的目的是為了減少 redolog 對(duì)寫入性能的影響袋励。想象一下,如果每次寫入產(chǎn)生的 redolog 都寫入磁盤当叭,即使是順序?qū)懭氩绻剩矔?huì)造成不小的影響。所以蚁鳖,如果一個(gè) transaction 中包含大量的寫入操作磺芭,最好將 log buffer 調(diào)大一些,避免不必要的磁盤 io 醉箕。
下面說說 commit 的執(zhí)行過程钾腺。由于在生產(chǎn)環(huán)境中,絕大多數(shù) mysql 實(shí)例都會(huì)開啟 binlog 讥裤,因此我們主要介紹開啟 binlog 時(shí) commit 的實(shí)行過程放棒。

commit 執(zhí)行過程

在開啟 binlog 的情況下, mysql 使用 2PC 來執(zhí)行 commit 過程己英,具體步驟如下:

  • 階段1:將 undolog 中的 transaction 狀態(tài)改為 prepared 间螟,并生成相應(yīng)的生成 redolog ,然后 flush log buffer 。
  • 階段2:將 transaction 寫入 binlog 厢破,然后告訴底層存儲(chǔ)引擎將 undolog 中的 transaction 狀態(tài)改為 commited 并生成 redo log 荣瑟。只要寫入binlog成功,就可以認(rèn)為事務(wù)寫入成功摩泪。

另外需要注意的是笆焰,此時(shí) mysql 使用 xid 來標(biāo)識(shí)該事務(wù)。

斷電恢復(fù)過程

完成了 prepare 階段见坑,寫入 binlog 之前斷電

這種情況下嚷掠, mysql 重新啟動(dòng)時(shí),會(huì)從 redolog 中讀出未 flush 到磁盤中的 page —— buffer pool 荞驴。然后從 redolog 重建這些內(nèi)存中的 page 不皆,以恢復(fù)斷電之前內(nèi)存的狀態(tài)。之后戴尸,mysql檢測(cè)到該事務(wù)并未提交粟焊,因此主動(dòng)執(zhí)行事務(wù)的回滾操作。

flush buffer pool 時(shí)斷電

即 flush page 的時(shí)候孙蒙。此時(shí)造成 page 一部分?jǐn)?shù)據(jù)寫入磁盤项棠,另一部分?jǐn)?shù)據(jù)未寫入磁盤。這時(shí)無法從 redo log 恢復(fù)異常 page 挎峦。原因是:之前提到 redo log 保存的page的修改記錄香追,即從原 page 到新 page 的 patch ,而此時(shí)原 page 已經(jīng)丟失(因?yàn)?page 的一部分?jǐn)?shù)據(jù)已經(jīng)寫入磁盤)坦胶,所以無法從 redo log 恢復(fù)透典。這時(shí)就要用到 double write buffer 了。每次 flush page 之前顿苇,都會(huì)先將 page flush 到一個(gè) double write buffer 峭咒,如果在真正 flush page 的時(shí)候出現(xiàn)異常,則可以從 double write buffer 恢復(fù)這個(gè) page 纪岁。

flush log buffer 時(shí)斷電

即 redolog 的flush凑队。由于 redolog 的 flush 是以扇區(qū)為單位進(jìn)行 flush 的,而扇區(qū)的寫入是原子性的(當(dāng)代的大部分硬盤都有這個(gè)能力)幔翰,因此不會(huì)造成部分寫入员帮、部分未寫入的情況周拐。

寫完 binlog 后斷電

上面說到睛约,寫入binlog時(shí)帝洪,便可認(rèn)為事務(wù)提交成功,就可以保證acid中的d做修。此時(shí)如果斷電霍狰,mysql在啟動(dòng)會(huì)執(zhí)行如下過程:

  1. 先從binlog中篩選出所有xid并創(chuàng)建hash_list
  2. 然后從存儲(chǔ)引擎(如innodb)中選出prepared狀態(tài)的transaction的xid列表list抡草。一般是從rollback segments(rseg) —— undo log ——中提取xid列表,然后在選出prepared狀態(tài)的蚓耽。
  3. 遍歷list的xid渠牲,如果xid在hash_list中則commit旋炒,否則rollback步悠。

寫入 binlog 時(shí)斷電

binlog 的寫入也是沒有 double write buffer 保護(hù)的,那么在寫入 binlog 的過程中如果發(fā)生了斷電瘫镇, mysql 是如何恢復(fù)的呢鼎兽。如上面介紹的寫入 binlog 后斷電恢復(fù)過程所示, mysql 會(huì)從 binlog 中選出所有的 xid 并創(chuàng)建恢復(fù)列表铣除,不過在遍歷 binlog 的過程中谚咬, mysql 同時(shí)也會(huì)尋找 last valid position ,并將這個(gè) position 之后的內(nèi)容都截取掉尚粘。因此择卦,如果某個(gè) transaction 寫入 binlog 的過程中斷電,并且有一部分未成功寫入郎嫁,則該 transaction 在 mysql 重啟時(shí)會(huì)被回滾秉继。

相關(guān)配置

這些配置是mysql5.7之后的默認(rèn)配置:

  • sync_binlog=1
  • innodb_support_xa=ON
  • innodb_flush_log_at_trx_commit=1。用于控制 log buffer 的刷新時(shí)機(jī)泽铛。

參考資料

《Mysql技術(shù)內(nèi)幕》
https://dev.mysql.com/doc/refman/5.7/en/glossary.html
mysql5.7源碼——sql/binlog.cc

作者: Normal Cock
鏈接: https://normal-cock.github.io/passages/mysql-power-off-and-recovery/
來源: normal-cock.github.io
著作權(quán)歸作者所有尚辑。商業(yè)轉(zhuǎn)載請(qǐng)聯(lián)系作者獲得授權(quán),非商業(yè)轉(zhuǎn)載請(qǐng)注明出處盔腔。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末杠茬,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子弛随,更是在濱河造成了極大的恐慌瓢喉,老刑警劉巖,帶你破解...
    沈念sama閱讀 223,002評(píng)論 6 519
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件舀透,死亡現(xiàn)場(chǎng)離奇詭異栓票,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)盐杂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,357評(píng)論 3 400
  • 文/潘曉璐 我一進(jìn)店門逗载,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人链烈,你說我怎么就攤上這事厉斟。” “怎么了强衡?”我有些...
    開封第一講書人閱讀 169,787評(píng)論 0 365
  • 文/不壞的土叔 我叫張陵擦秽,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我,道長(zhǎng)感挥,這世上最難降的妖魔是什么缩搅? 我笑而不...
    開封第一講書人閱讀 60,237評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮触幼,結(jié)果婚禮上硼瓣,老公的妹妹穿的比我還像新娘。我一直安慰自己置谦,他們只是感情好堂鲤,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,237評(píng)論 6 398
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著媒峡,像睡著了一般瘟栖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上谅阿,一...
    開封第一講書人閱讀 52,821評(píng)論 1 314
  • 那天半哟,我揣著相機(jī)與錄音,去河邊找鬼签餐。 笑死寓涨,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的贱田。 我是一名探鬼主播缅茉,決...
    沈念sama閱讀 41,236評(píng)論 3 424
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼男摧!你這毒婦竟也來了蔬墩?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,196評(píng)論 0 277
  • 序言:老撾萬榮一對(duì)情侶失蹤耗拓,失蹤者是張志新(化名)和其女友劉穎拇颅,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體乔询,經(jīng)...
    沈念sama閱讀 46,716評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡樟插,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,794評(píng)論 3 343
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了竿刁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片黄锤。...
    茶點(diǎn)故事閱讀 40,928評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖食拜,靈堂內(nèi)的尸體忽然破棺而出鸵熟,到底是詐尸還是另有隱情,我是刑警寧澤负甸,帶...
    沈念sama閱讀 36,583評(píng)論 5 351
  • 正文 年R本政府宣布流强,位于F島的核電站痹届,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏打月。R本人自食惡果不足惜队腐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,264評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奏篙。 院中可真熱鬧柴淘,春花似錦、人聲如沸报破。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,755評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽充易。三九已至,卻和暖如春荸型,著一層夾襖步出監(jiān)牢的瞬間盹靴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,869評(píng)論 1 274
  • 我被黑心中介騙來泰國(guó)打工瑞妇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留稿静,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,378評(píng)論 3 379
  • 正文 我出身青樓辕狰,卻偏偏與公主長(zhǎng)得像改备,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子蔓倍,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,937評(píng)論 2 361

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