學(xué)習(xí)日志-mysql的日志系統(tǒng)

經(jīng)常聽(tīng)DBA同事說(shuō),mysql可以恢復(fù)到半個(gè)月內(nèi)任意一秒的狀態(tài),是否好奇是怎么做到的?

我們還是從一個(gè)表的一條更新語(yǔ)句說(shuō)起蔚约,更新一個(gè)ID為主鍵和有一個(gè)整形字段c的表,ID = 1的行凶朗,例如下面這條更新語(yǔ)句:

update T set c = c+1 where ID = 1;

先附上mysql的邏輯架構(gòu)圖:


mysql邏輯架構(gòu)圖.png

更新語(yǔ)句會(huì)按照基本架構(gòu)流程走一遍睹晒。

mysql的更新流程趟庄,涉及兩個(gè)重要的日志模塊,也就是我們今天要討論的日志系統(tǒng)的主要構(gòu)成:redo log(重做日志)和bin log(歸檔日志)册招。雖然非DBA的同學(xué)基本不會(huì)關(guān)注這兩個(gè)日志作用岔激,但是redo log和bin log在設(shè)計(jì)上有很多可以借鑒的地方,這些設(shè)計(jì)思路可以用的平時(shí)的應(yīng)用開(kāi)發(fā)中是掰。

重要的日志模塊:redo log

mysql的數(shù)據(jù)更新虑鼎,最終都要將數(shù)據(jù)寫(xiě)進(jìn)磁盤(pán)。如果每一次更新键痛,都要直接寫(xiě)進(jìn)磁盤(pán)炫彩,就要在磁盤(pán)找到對(duì)應(yīng)的那條記錄,然后再更新絮短,整個(gè)過(guò)程IO成本江兢、查找成本都會(huì)很高。為了解決這個(gè)問(wèn)題丁频,mysql的設(shè)計(jì)者就采用了redo log來(lái)提升更新效率杉允。

log和磁盤(pán)的配合寫(xiě)入,就是mysql里常說(shuō)的WAL技術(shù)席里,WAL全程是Write-Ahead Logging叔磷,它的關(guān)鍵思路是先寫(xiě)日志,再寫(xiě)磁盤(pán)奖磁。
具體來(lái)說(shuō)改基,當(dāng)有一條記錄需要更新的時(shí)候嗎,InnoDB會(huì)先將記錄寫(xiě)到redo log里咖为,并更新內(nèi)存秕狰,這個(gè)時(shí)候稠腊,更新就算完成了。同時(shí)鸣哀,InnoDB引擎會(huì)在適當(dāng)?shù)臅r(shí)候架忌,將這個(gè)操作記錄更新到磁盤(pán)里面,而這個(gè)更新往往是操作系統(tǒng)比價(jià)空閑的時(shí)候诺舔。

如果某個(gè)時(shí)刻操作不是很多鳖昌,InnoDB可以等空閑的時(shí)候再寫(xiě)入磁盤(pán),但如果操作很多低飒,log中又寫(xiě)滿了许昨,該怎么辦呢?
InnoDB的redo log是固定大小的文件褥赊,比如可以配置為一組4個(gè)文件糕档,每個(gè)文件大小是1GB,那么就總共可以記錄4GB的操作拌喉。redo log從頭開(kāi)始寫(xiě)速那,寫(xiě)到末尾就又回到開(kāi)頭循環(huán)寫(xiě),如下圖所示:


redo log示意圖.png

write pos是當(dāng)前的記錄的位置尿背,一邊寫(xiě)一邊后移端仰,寫(xiě)到3號(hào)文件末尾就又回到0號(hào)文件開(kāi)頭。check point是當(dāng)前要擦除的位置田藐,也是往后推移并且循環(huán)的荔烧,擦除記錄之前要把記錄更新到數(shù)據(jù)文件。

write pos和check point之間是空閑的部分汽久,可以用來(lái)記錄新的操作鹤竭。如果write pos追上了check point,標(biāo)識(shí)日志已經(jīng)寫(xiě)滿 了景醇,這個(gè)時(shí)候不能再執(zhí)行更新臀稚,得停下來(lái)先擦掉一些記錄,把check point往前推進(jìn)一下三痰。

有了redo log吧寺,InnoDB就可以保證即時(shí)數(shù)據(jù)庫(kù)發(fā)生異常重啟,之前提交的記錄都不會(huì)丟失散劫,這個(gè)能力稱之為crash-safe撮执。

重要的日志模塊:binlog

從mysql的邏輯架構(gòu)圖來(lái)看,其實(shí)就兩塊:一塊是Server層舷丹,它主要做的是mysql功能層面的事情;另一塊是引擎層蜓肆,負(fù)責(zé)存儲(chǔ)相關(guān)的具體事宜颜凯。
上面我們聊到的redo log是InnoDB引擎特有的日志谋币,而Server層也有自己的日志--binlog(歸檔日志)。

為什么會(huì)有兩份日志系統(tǒng)呢症概?
因?yàn)樽铋_(kāi)始mysql里沒(méi)有InnoDB引擎蕾额。mysql自帶的引擎是MyISAM,但是MyISAM沒(méi)有crash-safe能力彼城,binlog日志只能用于歸檔诅蝶。而InnoDB是另個(gè)一公司以插件形式引入mysql的,既然只依靠binlog是沒(méi)有crash-safe能力的募壕,所以InnoDB使用另外一套日志系統(tǒng)--也就是redo log來(lái)實(shí)現(xiàn)crash safe能力调炬。

這兩種日志系統(tǒng)有以下三點(diǎn)不同。

  1. redo log是InnoDB引擎特有的舱馅;binlog是mysql的server層實(shí)現(xiàn)的缰泡,所有引擎都可以使用
  2. redo log是物理日志,記錄的是在“在某個(gè)數(shù)據(jù)頁(yè)上做了什么修改”代嗤;binlog是邏輯日志棘钞,記錄的是這個(gè)語(yǔ)句的原始邏輯,比如“給ID = 1的這一行加1”.
  3. redo log是循環(huán)寫(xiě)的干毅,空間固定會(huì)用完宜猜;binlog是可以追加寫(xiě)入的∠醴辏“追加寫(xiě)入”是指binlog文件寫(xiě)到一定大小后會(huì)切換到下一個(gè)姨拥,并不會(huì)覆蓋以前的日志。

有了對(duì)這兩個(gè)日志的概念性理解趴捅,我們?cè)賮?lái)看執(zhí)行器和InnoDB引擎在執(zhí)行這個(gè)簡(jiǎn)單update語(yǔ)句時(shí)的內(nèi)部流程垫毙。

  1. 執(zhí)行器先找引擎取ID=1這一行。ID是主鍵拱绑,引擎直接使用樹(shù)搜索到這一樣综芥。如果ID=1的這一行所在的數(shù)據(jù)頁(yè)本來(lái)就在內(nèi)存中,就直接返回給執(zhí)行器猎拨;否則膀藐,需要先從磁盤(pán)讀入內(nèi)存,然后再返回红省。
  2. 執(zhí)行器拿到引擎給的行數(shù)據(jù)额各,把這個(gè)數(shù)據(jù)加上1,比如原來(lái)是N吧恃,現(xiàn)在就是N+1虾啦,得到新的一行數(shù)據(jù),再調(diào)用引擎接口寫(xiě)入這行新數(shù)據(jù)。
  3. 引擎將這行新數(shù)據(jù)更新到內(nèi)存中傲醉,同時(shí)將這個(gè)更新操作記錄到redo log里面蝇闭,此時(shí)的redo log處于prepare狀態(tài)。然后告知執(zhí)行器完成了硬毕,可以隨時(shí)提交事務(wù)呻引。
  4. 執(zhí)行器生成這個(gè)操作的binlog,并把binlog寫(xiě)入磁盤(pán)吐咳。
  5. 執(zhí)行器調(diào)用引擎的提交事務(wù)接口逻悠,引擎把剛剛寫(xiě)入的redo log改成提交(commit)狀態(tài),更新完成韭脊。

這里給出一個(gè)update語(yǔ)句的執(zhí)行流程圖童谒,圖中淺色框表示在InnoDB內(nèi)部執(zhí)行的,深色框表示在執(zhí)行器中執(zhí)行的乾蓬。


update語(yǔ)句執(zhí)行流程.png

你可能注意到了惠啄,最后三步有點(diǎn)“繞”,將redo log的寫(xiě)入拆分成了兩個(gè)步驟:prepare和commit任内,這就是“兩階段提交”撵渡。

兩階段提交

為什么必須有“兩階段提交”呢?
這是為了讓兩份日志之間保持邏輯一致死嗦。要說(shuō)明這個(gè)問(wèn)題趋距,我們得從開(kāi)篇的問(wèn)題說(shuō)起:怎樣讓數(shù)據(jù)庫(kù)恢復(fù)到半個(gè)月內(nèi)任意一秒的狀態(tài)?

我們前面說(shuō)過(guò)了越除,binlog日志會(huì)記錄所有的邏輯操作节腐,并且采用“追加寫(xiě)”的方式。如果你的DBA承諾說(shuō)半個(gè)月內(nèi)可以恢復(fù)摘盆,那么備份系統(tǒng)中一定會(huì)保存最近半個(gè)月的所有binlog翼雀,同時(shí)系統(tǒng)會(huì)定期做整庫(kù)備份。這里的“定期”取決于系統(tǒng)的重要性孩擂,可以是一天一備狼渊,也可以是一周一備。
當(dāng)需要回到指定的某一秒時(shí)类垦,比如某天下午兩點(diǎn)發(fā)現(xiàn)中午十二點(diǎn)有一次誤刪表狈邑,需要找回?cái)?shù)據(jù),那你可以這么做:

  1. 首先蚤认,找到最近的一次全量備份米苹,如果你運(yùn)氣好,可能就是昨天晚上的一個(gè)備份砰琢,從這個(gè)備份恢復(fù)到臨時(shí)庫(kù)蘸嘶;
  2. 然后良瞧,從備份的時(shí)間點(diǎn)開(kāi)始,將備份的binlog一次取出來(lái)亏较,重放到中午誤刪表之前的那個(gè)時(shí)刻莺褒。

這樣你的臨時(shí)庫(kù)就跟誤刪之前的線上庫(kù)一樣了,然后你就可以把表數(shù)據(jù)從臨時(shí)庫(kù)取出來(lái)雪情,按需要恢復(fù)到線上庫(kù)去。

說(shuō)完了數(shù)據(jù)恢復(fù)過(guò)程你辣,我們回來(lái)說(shuō)為什么日志需要“兩階段提交”巡通。這里不妨用反證法解釋一下。

由于redo log和binlog是兩個(gè)獨(dú)立的邏輯舍哄,如果不用兩階段提交宴凉,要么先寫(xiě)完redo log再寫(xiě)binlog,或者采用過(guò)來(lái)的順序表悬。我們看看這樣會(huì)有什么問(wèn)題弥锄。

仍然用前面的update來(lái)做栗子。假設(shè)當(dāng)前ID=1的行蟆沫,字段c的值是0籽暇,再假設(shè)執(zhí)行update語(yǔ)句過(guò)程中在寫(xiě)完第一個(gè)日志之后,第二個(gè)日志還沒(méi)有寫(xiě)完期間發(fā)生了crash饭庞,會(huì)出現(xiàn)什么情況呢戒悠?

  1. 先寫(xiě)redo log后寫(xiě)binlog。假設(shè)在redo log寫(xiě)完舟山,binlog沒(méi)有寫(xiě)完的時(shí)候绸狐,發(fā)生了異常重啟。按照之前的邏輯累盗,從redo log恢復(fù)回來(lái)的數(shù)據(jù)寒矿,恢復(fù)后這一行的數(shù)據(jù)c的值是1。
    但是由于binlog沒(méi)有記錄這個(gè)語(yǔ)句若债,因此之后備份日志的時(shí)候符相,存起來(lái)的binlog就沒(méi)有這條語(yǔ)句。
    然后如果使用這個(gè)binlog來(lái)恢復(fù)臨時(shí)庫(kù)拆座,由于binlog的丟失主巍,這個(gè)臨時(shí)庫(kù)就少了一次更新,導(dǎo)致了數(shù)據(jù)錯(cuò)誤挪凑。
  2. 先寫(xiě)binlog再寫(xiě)redo log孕索。如果在binlog寫(xiě)完之后crash,由于redo log還沒(méi)有寫(xiě)躏碳,崩潰以后這個(gè)事務(wù)無(wú)效搞旭,所以這一行c的值是0,單binlog里面已經(jīng)記錄了“把c從0改成1”這個(gè)日志。所以之后用binlog來(lái)恢復(fù)的時(shí)候就多了一個(gè)事務(wù)出來(lái)肄渗,恢復(fù)出來(lái)的這樣c的值就是1镇眷,與原庫(kù)不同。

你可能會(huì)覺(jué)得翎嫡,這個(gè)概率很低欠动,平時(shí)也沒(méi)有動(dòng)不動(dòng)就要恢復(fù)臨時(shí)庫(kù)的場(chǎng)景呀。

其實(shí)不是的惑申,不止誤操作的恢復(fù)數(shù)據(jù)具伍,當(dāng)你擴(kuò)容的時(shí)候,就是需要再多搭建一些備庫(kù)來(lái)增加系統(tǒng)的讀能力的時(shí)候圈驼,現(xiàn)在常見(jiàn)的做法也是用全量備份加上應(yīng)用binlog來(lái)實(shí)現(xiàn)的人芽。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
禁止轉(zhuǎn)載,如需轉(zhuǎn)載請(qǐng)通過(guò)簡(jiǎn)信或評(píng)論聯(lián)系作者绩脆。
  • 序言:七十年代末萤厅,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子靴迫,更是在濱河造成了極大的恐慌惕味,老刑警劉巖,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件矢劲,死亡現(xiàn)場(chǎng)離奇詭異赦拘,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)芬沉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)躺同,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人丸逸,你說(shuō)我怎么就攤上這事蹋艺。” “怎么了黄刚?”我有些...
    開(kāi)封第一講書(shū)人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵捎谨,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我憔维,道長(zhǎng)涛救,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任业扒,我火速辦了婚禮检吆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘程储。我一直安慰自己蹭沛,他們只是感情好臂寝,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著摊灭,像睡著了一般咆贬。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上帚呼,一...
    開(kāi)封第一講書(shū)人閱讀 52,713評(píng)論 1 312
  • 那天掏缎,我揣著相機(jī)與錄音,去河邊找鬼萝挤。 笑死御毅,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的怜珍。 我是一名探鬼主播,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼凤粗,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼酥泛!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起嫌拣,我...
    開(kāi)封第一講書(shū)人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤柔袁,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后异逐,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體捶索,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年灰瞻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了腥例。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡酝润,死狀恐怖燎竖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情要销,我是刑警寧澤构回,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布,位于F島的核電站疏咐,受9級(jí)特大地震影響纤掸,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜浑塞,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一借跪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧缩举,春花似錦垦梆、人聲如沸匹颤。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)印蓖。三九已至,卻和暖如春京腥,著一層夾襖步出監(jiān)牢的瞬間赦肃,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工公浪, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留他宛,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓欠气,卻偏偏與公主長(zhǎng)得像厅各,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子预柒,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

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