15 - 日志的相關(guān)問題

關(guān)鍵字

日志、索引

這一章是專欄老師的答疑課逗威,在這一節(jié)中,主要解決了一些關(guān)于日志和索引的疑惑岔冀。

日志相關(guān)問題

在第二篇文章中凯旭,講到了 binlog 和 redo log,這兩個(gè)日志使用了兩階段提交使套。這樣的方法可以解決崩潰恢復(fù)的問題罐呼。在這里,就詳細(xì)分析一下在 MySQL 發(fā)生異常重啟的時(shí)候侦高,是怎么保證數(shù)據(jù)完整性的嫉柴。

首先看一下在第二篇文章中的圖:
15-崩潰恢復(fù).jpg

在這里,我們就分析一下奉呛,在兩階段提交的不同時(shí)刻计螺,MySQL 異常重啟會(huì)出現(xiàn)什么現(xiàn)象。

  • 如果在 時(shí)刻A 發(fā)生重啟瞧壮,也就是 redo log 處于 prepare 階段之后登馒、寫 binlog 之前發(fā)生了崩潰。此時(shí)咆槽,由于 binlog 還沒寫陈轿,redo log 沒提交,所以在恢復(fù)的時(shí)候,這個(gè)事務(wù)會(huì)回滾麦射。

  • 如果 時(shí)刻B 發(fā)生重啟蛾娶,也就是在 binlog 寫完,redo log 還沒有 commit 時(shí)發(fā)生了崩潰潜秋。此時(shí)有兩個(gè)判斷規(guī)則:
    1.如果 redo log 里的事務(wù)完整蛔琅,即已經(jīng)有了 commit,則直接提交半等。
    2.如果 redo log 的事務(wù)只有 prepare,則需要判斷 binlog 是否存在且完整呐萨。如果完整杀饵,提交事務(wù);如果不完整谬擦,回滾切距。

在 時(shí)刻B,已經(jīng)有了完整的 binlog惨远,崩潰恢復(fù)的事務(wù)會(huì)被提交谜悟。

追問:MySQL 怎么知道 binlog 是否完整?

答:一個(gè)事務(wù)的 binlog 是有完整格式的北秽,所以葡幸,MySQL 有辦法驗(yàn)證事務(wù) binlog 的完整性。

追問:redo log 和 binlog 是如何關(guān)聯(lián)起來的贺氓?

答:它們有一個(gè)共同的字段蔚叨,XID。崩潰恢復(fù)的時(shí)候辙培,會(huì)順序掃描 redo log:

  • 如果 redo log 中既有 prepare 又有 commit 蔑水,就直接提交。
  • 如果只有 prepare扬蕊,而沒有 commit搀别,則需要拿著 redo log 中的 XID 去 binlog 中尋找對應(yīng)事務(wù)。
追問:prepare 的 redo log + 完整的 binlog --> 重啟后提交這個(gè)事務(wù)尾抑。為什么不設(shè)置為回滾歇父?

答:在 時(shí)刻B,binlog 已經(jīng)寫入了再愈,之后就會(huì)被從庫(或用這個(gè) binlog 恢復(fù)出來的庫)使用庶骄。所以,在主庫也要提交這個(gè)事務(wù)践磅,以保持主庫和備庫的數(shù)據(jù)一致性单刁。

追問:為什么要這樣設(shè)計(jì)兩階段提交呢?為什么不先寫完 redo log,再寫 binlog羔飞。崩潰恢復(fù)的時(shí)候肺樟,要求兩個(gè)日志都完整才可以回復(fù)。是不是也是一樣的邏輯逻淌?

答:不是的么伯,對于 InnoDB 引擎來說,如果 redo log 提交完成了卡儒,事務(wù)就不能回滾(如果這還允許回滾田柔,就可能覆蓋掉別的事務(wù)的更新)。而如果 redo log 直接提交骨望,然后 binlog 寫入的時(shí)候失敗硬爆,InnoDB 又回滾不了,數(shù)據(jù)和 binlog 日志又不一致了擎鸠。

所以缀磕,只有當(dāng)每個(gè)人都說“我 OK ”的時(shí)候,再一起提交劣光。

追問:為什么不能用 binlog 既支持崩潰回復(fù)袜蚕,又支持歸檔呢?

注:言下之意是:只保留 binlog绢涡,然后可以把提交流程改成這樣:… -> “數(shù)據(jù)更新到內(nèi)存” -> “寫 binlog” -> “提交事務(wù)”牲剃,是不是也可以提供崩潰恢復(fù)的能力?

答:不可以雄可。這有歷史原因實(shí)現(xiàn)上的原因兩個(gè)方面颠黎。

歷史原因:InnoDB 并不是 MySQL 的原生引擎。MySQL 的原生 MyISAM 引擎并不支持崩潰恢復(fù)滞项。

InnoDB 作為插件加入 InnoDB 之后狭归,才通過 redo log 提供了崩潰回復(fù)的功能。

實(shí)現(xiàn)上的原因:在下面的圖中文判,沒有 redo log过椎,如果在指定的地方發(fā)生崩潰,會(huì)出現(xiàn)一些問題:

15-只有binlog.jpg

在發(fā)生 crash 時(shí)戏仓,binlog2 寫完了疚宇,但是 事務(wù)2 還沒有 commit。

重啟后赏殃,事務(wù)2 會(huì)進(jìn)行回滾敷待,然后使用 binlog2 補(bǔ)回來;但是對于 事務(wù)1 來說仁热,因?yàn)橐呀?jīng) commit榜揖,所以并不會(huì)使用 binlog1。

InnoDB 使用的是 WAL,執(zhí)行事務(wù)的時(shí)候举哟,寫完內(nèi)存和日志思劳,事務(wù)就算完成了,注意妨猩,此時(shí)內(nèi)存中的數(shù)據(jù)并不一定已經(jīng)刷到了磁盤中潜叛。

所以,如果在圖中的位置發(fā)生崩潰壶硅,事務(wù)1 可能會(huì)丟失威兜,而且是數(shù)據(jù)頁級別的丟失。所以庐椒,目前來說椒舵,binlog 還不能支持崩潰恢復(fù)。

追問:能不能只用 redo log扼睬,不用 binlog逮栅?

答:如果只從崩潰恢復(fù)的角度來講是可以的悴势。關(guān)掉 binlog 之后系統(tǒng)依然是 crash-safe 的窗宇。

但是,binlog 擁有很多其它功能特纤,比如歸檔军俊、比如在異構(gòu)系統(tǒng)中消費(fèi) binlog 來更新自己的數(shù)據(jù)。如果關(guān)掉 binlog捧存,這些功能都無法使用粪躬。

總之,很多系統(tǒng)機(jī)制都依賴 binlog昔穴,所以從生態(tài)的角度來看镰官,binlog 必不可少。

追問:redo log 設(shè)置多大吗货?

答:如果 redo log 設(shè)置太小泳唠,會(huì)很快被寫滿,然后觸發(fā)強(qiáng)行刷 redo log宙搬,這會(huì)降低性能笨腥。

所以,如果你的磁盤足夠勇垛,就不要太小氣了脖母,直接將 redo log 設(shè)置為 4 個(gè)文件、每個(gè)文件 1GB 吧闲孤。

追問:數(shù)據(jù)的最終落盤谆级,是從 redo log 更新還是從 buffer pool 更新呢?

答:實(shí)際上,redo log 并沒有記錄數(shù)據(jù)頁的完整數(shù)據(jù)哨苛,所以最終落盤鸽凶,不可能是由 redo log 更新過去的。

  • 臟頁落盤和 redo log 毫無關(guān)系建峭。
  • 在崩潰恢復(fù)中玻侥,InnoDB 如果判斷一個(gè)數(shù)據(jù)頁可能丟失更新,就會(huì)將它讀到內(nèi)存中亿蒸,然后用 redo log 更新內(nèi)存內(nèi)容凑兰。更新后,就又變成了臟頁落盤的問題边锁,這就和 redo log 無關(guān)了姑食。

小結(jié)

這是一篇答疑文章,主要回答了日志的相關(guān)問題茅坛。實(shí)際上音半,專欄文章還講到了一個(gè)比較復(fù)雜的問題,但是我并沒有理解那個(gè)問題贡蓖,所以在這里就沒有寫出曹鸠。如果對之后的問題感興趣,可以到專欄中找一找斥铺。

上期問題

上期的問題是彻桃,用一個(gè)計(jì)數(shù)表記錄一個(gè)業(yè)務(wù)表的總行數(shù),在往業(yè)務(wù)表插入數(shù)據(jù)的時(shí)候晾蜘,需要給計(jì)數(shù)值加 1邻眷。

邏輯實(shí)現(xiàn)上是啟動(dòng)一個(gè)事務(wù),執(zhí)行兩個(gè)語句:

  • insert into 數(shù)據(jù)表剔交;
  • update 計(jì)數(shù)表肆饶,計(jì)數(shù)值加 1。

從系統(tǒng)并發(fā)能力的角度考慮岖常,怎么安排這兩個(gè)語句的順序驯镊。

解答:

并發(fā)系統(tǒng)性能的角度考慮,應(yīng)該先插入操作記錄腥椒,再更新計(jì)數(shù)表阿宅。
知識(shí)點(diǎn)在《行鎖功過:怎么減少行鎖對性能的影響?》
因?yàn)楦掠?jì)數(shù)表涉及到行鎖的競爭笼蛛,先插入再更新能最大程度地減少事務(wù)之間的鎖等待洒放,提升并發(fā)度。

本期思考

我們創(chuàng)建了一個(gè)簡單的表 t滨砍,并插入一行往湿,然后對這一行做修改妖异。

mysql> CREATE TABLE `t` (
`id` int(11) NOT NULL primary key auto_increment,
`a` int(11) DEFAULT NULL
) ENGINE=InnoDB;
insert into t values(1,2);

這時(shí)候,表 t 里有唯一的一行數(shù)據(jù) (1,2)领追。假設(shè)他膳,我現(xiàn)在要執(zhí)行:

mysql> update t set a=2 where id=1;

你會(huì)看到這樣的結(jié)果:
15-課后思考.png

結(jié)果顯示,匹配 (rows matched) 了一行绒窑,修改 (Changed) 了 0 行棕孙。

僅從現(xiàn)象上看,MySQL 內(nèi)部在處理這個(gè)命令的時(shí)候些膨,可以有以下三種選擇:

  1. 更新都是先讀后寫的蟀俊,MySQL 讀出數(shù)據(jù),發(fā)現(xiàn) a 的值本來就是 2订雾,不更新肢预,直接返回,執(zhí)行結(jié)束洼哎;
  2. MySQL 調(diào)用了 InnoDB 引擎提供的“修改為 (1,2)”這個(gè)接口烫映,但是引擎發(fā)現(xiàn)值與原來相同,不更新噩峦,直接返回锭沟;
  3. InnoDB 認(rèn)真執(zhí)行了“把這個(gè)值修改成 (1,2)"這個(gè)操作,該加鎖的加鎖壕探,該更新的更新冈钦。

你覺得實(shí)際情況會(huì)是以上哪種呢郊丛?你可否用構(gòu)造實(shí)驗(yàn)的方式李请,來證明你的結(jié)論?進(jìn)一步地厉熟,可以思考一下导盅,MySQL 為什么要選擇這種策略呢?


以上就是本節(jié)內(nèi)容揍瑟,愿你能解決疑問白翻。

注:本文章的主要內(nèi)容來自我對極客時(shí)間app的《MySQL實(shí)戰(zhàn)45講》專欄的總結(jié),我使用了大量的原文绢片、代碼和截圖滤馍,如果想要了解具體內(nèi)容,可以前往極客時(shí)間

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末底循,一起剝皮案震驚了整個(gè)濱河市巢株,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌熙涤,老刑警劉巖阁苞,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件困檩,死亡現(xiàn)場離奇詭異,居然都是意外死亡那槽,警方通過查閱死者的電腦和手機(jī)悼沿,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來骚灸,“玉大人糟趾,你說我怎么就攤上這事∩跎” “怎么了拉讯?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長鳖藕。 經(jīng)常有香客問我魔慷,道長,這世上最難降的妖魔是什么著恩? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任院尔,我火速辦了婚禮,結(jié)果婚禮上喉誊,老公的妹妹穿的比我還像新娘邀摆。我一直安慰自己,他們只是感情好伍茄,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布栋盹。 她就那樣靜靜地躺著,像睡著了一般敷矫。 火紅的嫁衣襯著肌膚如雪例获。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天曹仗,我揣著相機(jī)與錄音榨汤,去河邊找鬼。 笑死怎茫,一個(gè)胖子當(dāng)著我的面吹牛收壕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播轨蛤,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蜜宪,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了祥山?” 一聲冷哼從身側(cè)響起圃验,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎枪蘑,沒想到半個(gè)月后损谦,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體岖免,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年照捡,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了颅湘。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,841評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡栗精,死狀恐怖闯参,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情悲立,我是刑警寧澤鹿寨,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站薪夕,受9級特大地震影響脚草,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜原献,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一馏慨、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧姑隅,春花似錦写隶、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鄙陡,卻和暖如春冕房,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背柔吼。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工毒费, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丙唧,地道東北人愈魏。 一個(gè)月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像想际,于是被迫代替她去往敵國和親培漏。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,781評論 2 354