MySQL redo & undo log-這一篇就夠了

寫在前面

本文是對于網(wǎng)上各個(gè)對redo和undo log日志解析的總結(jié),參考文章列表在最后卫旱。

事務(wù)的4大特性:原子性惭每、一致性骨饿、隔離性和持久性亏栈。
事務(wù)的隔離性由鎖機(jī)制實(shí)現(xiàn)。
原子性宏赘、一致性和持久性由事務(wù)的redo 日志和undo 日志來保證绒北。
redo log:物理日志,記錄的是數(shù)據(jù)頁的物理修改察署,而不是某一行或某幾行修改成什么樣子闷游,它用來恢復(fù)提交后的物理數(shù)據(jù)頁(恢復(fù)數(shù)據(jù)頁,且只能恢復(fù)到最后一次提交的位置)贴汪。
undo log:用來回滾行記錄到某個(gè)版本脐往。undo log一般是邏輯日志,根據(jù)每行數(shù)據(jù)的修改前數(shù)據(jù)和修改操作記錄扳埂。

redo log

redo log和二進(jìn)制日志的區(qū)別

二進(jìn)制日志相關(guān)內(nèi)容业簿,參考:MariaDB/MySQL的二進(jìn)制日志

redo log不是二進(jìn)制日志阳懂。雖然二進(jìn)制日志中也記錄了innodb表的很多操作梅尤,也能實(shí)現(xiàn)重做的功能,但是它們之間有很大區(qū)別岩调。

  1. 二進(jìn)制日志是在存儲引擎的上層產(chǎn)生的巷燥,不管是什么存儲引擎,對數(shù)據(jù)庫進(jìn)行了修改都會產(chǎn)生二進(jìn)制日志誊辉。而redo log是innodb層產(chǎn)生的矾湃,只記錄該存儲引擎中表的修改。并且二進(jìn)制日志先于****redo log****被記錄堕澄。
  2. 二進(jìn)制日志記錄邏輯性的語句邀跃。即便它是基于行格式的記錄方式,其本質(zhì)也還是邏輯的SQL設(shè)置蛙紫,如該行記錄的每列的值是多少拍屑。而redo log是在物理格式上的日志,它記錄的是數(shù)據(jù)庫中每個(gè)頁的修改坑傅。
  3. 二進(jìn)制日志只在每次事務(wù)提交的時(shí)候一次性寫入緩存中的日志"文件"僵驰。而redo log在事務(wù)中就會產(chǎn)生,并且在對數(shù)據(jù)真正修改前先寫入緩存中的redo log中唁毒,然后才對內(nèi)存中的數(shù)據(jù)執(zhí)行修改操作蒜茴;而且保證在發(fā)出事務(wù)提交指令時(shí),先向緩存中的redo log寫入到redo log file中浆西,redo log file 寫入完成后才執(zhí)行提交動作粉私。
  4. 因?yàn)槎M(jìn)制日志只在提交的時(shí)候一次性寫入,所以二進(jìn)制日志中的記錄方式和提交順序有關(guān)近零,且一次提交對應(yīng)一次記錄诺核。而redo log中是記錄的物理頁的修改抄肖,redo log file中同一個(gè)事務(wù)可能多次記錄,最后一個(gè)提交的事務(wù)記錄會覆蓋所有未提交的事務(wù)記錄窖杀。例如事務(wù)T1漓摩,可能在redo log中記錄了 T1-1,T1- 2,T1-3,T1* 共4個(gè)操作入客,其中 T1* 表示最后提交時(shí)的日志記錄管毙,所以對應(yīng)的數(shù)據(jù)頁最終狀態(tài)是 T1* 對應(yīng)的操作結(jié)果。而且redo log是并發(fā)寫入的痊项,不同事務(wù)之間的不同版本的記錄會穿插寫入到redo log文件中锅风,例如可能redo log的記錄方式如下: T1-1,T1-2,T2-1,T2- 2,T2,T1-3,T1

Redo 的類型

重做日志(redo log)用來保證事務(wù)的持久性鞍泉,即事務(wù)ACID中的D。實(shí)際上它可以分為以下兩種類型:

  • 物理Redo日志
  • 邏輯Redo日志

在InnoDB存儲引擎中肮帐,大部分情況下 Redo是物理日志咖驮,記錄的是數(shù)據(jù)頁的物理變化
邏輯Redo日志训枢,不記錄頁面的實(shí)際修改內(nèi)容托修,而只記錄修改頁面的一類操作,比如新建數(shù)據(jù)頁恒界。關(guān)于邏輯Redo日志涉及更加底層的內(nèi)容睦刃,這里我們只需要記住絕大數(shù)情況下,Redo是物理日志即可十酣,DML對頁的修改操作涩拙,均需要記錄Redo。

Redo 的作用

Redo log的主要作用是用于數(shù)據(jù)庫的崩潰恢復(fù)耸采。

Redo 的組成

Redo log分為兩部分:

  • redo log buffer:在內(nèi)存中,易失兴泥。
  • redo log file:在磁盤中,是持久的虾宇。

什么時(shí)候?qū)慠edo log?

上面那張圖簡單地體現(xiàn)了Redo的寫入流程搓彻,這里再細(xì)說下寫入Redo的時(shí)機(jī):

  • 在數(shù)據(jù)頁修改完成之后,在臟頁刷出磁盤之前嘱朽,寫入redo日志旭贬。注意的是先修改數(shù)據(jù),后寫日志
  • redo日志比數(shù)據(jù)頁先寫回磁盤
  • 聚集索引搪泳、二級索引稀轨、undo頁面的修改,均需要記錄Redo日志森书。

Redo的整體流程

下面以一個(gè)更新事務(wù)為例靶端,宏觀執(zhí)行流程如下圖所示:

  • 1:將原始數(shù)據(jù)從磁盤中讀入內(nèi)存中谎势,修改數(shù)據(jù)在內(nèi)存中的拷貝
  • 2:生成一條redo log并寫入redo log buffer,記錄的是數(shù)據(jù)被修改后的值
  • 3:當(dāng)事務(wù)commit時(shí)杨名,將redo log buffer中的內(nèi)容刷新到 redo log file脏榆,對 redo log file采用追加寫的方式
  • 4:定期將內(nèi)存中修改的數(shù)據(jù)刷新到磁盤中

redo如何保證事務(wù)的持久性?

InnoDB是事務(wù)的存儲引擎台谍,其通過Force Log at Commit 機(jī)制實(shí)現(xiàn)事務(wù)的持久性须喂。
即當(dāng)事務(wù)提交時(shí),先將 redo log buffer 寫入到 redo log file 進(jìn)行持久化趁蕊,待事務(wù)的commit操作完成時(shí)才算完成坞生。這種做法也被稱為 Write-Ahead Log(預(yù)先日志持久化):在持久化一個(gè)數(shù)據(jù)頁之前,先將內(nèi)存中相應(yīng)的日志頁持久化掷伙。

為了保證每次日志都寫入redo log file是己,在每次將redo buffer寫入redo log file之后,默認(rèn)情況下任柜,InnoDB存儲引擎都需要調(diào)用一次 fsync操作,因?yàn)閞edo log并沒有 O_DIRECT選項(xiàng)卒废,所以redo log先寫入到文件系統(tǒng)緩存。為了確保redo log寫入到磁盤宙地,必須進(jìn)行一次 fsync操作摔认。fsync是一種系統(tǒng)調(diào)用操作,其fsync的效率取決于磁盤的性能宅粥,因此磁盤的性能也影響了事務(wù)提交的性能参袱,也就是數(shù)據(jù)庫的性能。
(O_DIRECT選項(xiàng)是在Linux系統(tǒng)中的選項(xiàng)秽梅,使用該選項(xiàng)后抹蚀,對文件進(jìn)行直接IO操作,不經(jīng)過文件系統(tǒng)緩存风纠,直接寫入磁盤)

上面提到的Force Log at Commit機(jī)制就是靠InnoDB存儲引擎提供的參數(shù) innodb_flush_log_at_trx_commit來控制的况鸣,該參數(shù)可以控制 redo log刷新到磁盤的策略,設(shè)置該參數(shù)值也可以允許用戶設(shè)置非持久性的情況發(fā)生竹观,具體如下:

  • 當(dāng)設(shè)置參數(shù)為1時(shí)镐捧,(默認(rèn)為1),表示事務(wù)提交時(shí)必須調(diào)用一次 fsync 操作臭增,最安全的配置懂酱,保障持久性。
  • 當(dāng)設(shè)置參數(shù)為2時(shí)誊抛,則在事務(wù)提交時(shí)只做 write 操作列牺,只保證將redo log buffer寫到系統(tǒng)的頁面緩存中,不進(jìn)行fsync操作拗窃,因此如果MySQL數(shù)據(jù)庫宕機(jī)時(shí) 不會丟失事務(wù)瞎领,但操作系統(tǒng)宕機(jī)則可能丟失事務(wù)泌辫。
  • 當(dāng)設(shè)置參數(shù)為0時(shí),表示事務(wù)提交時(shí)不進(jìn)行寫入redo log file操作九默,這個(gè)操作僅在master thread 中完成震放,而在master thread中每1秒進(jìn)行一次重做日志的fsync操作,因此實(shí)例 crash 最多丟失1秒鐘內(nèi)的事務(wù)驼修。(master thread是負(fù)責(zé)將緩沖池中的數(shù)據(jù)異步刷新到磁盤殿遂,保證數(shù)據(jù)的一致性)
    具體過程如下:


fsyncwrite操作實(shí)際上是系統(tǒng)調(diào)用函數(shù),在很多持久化場景都有使用到乙各,比如 Redis 的AOF持久化中也使用到兩個(gè)函數(shù)墨礁。fsync操作將數(shù)據(jù)提交到硬盤中,強(qiáng)制硬盤同步耳峦,將一直阻塞到寫入硬盤完成后返回恩静,大量進(jìn)行fsync操作就有性能瓶頸,而write操作將數(shù)據(jù)寫到系統(tǒng)的頁面緩存后立即返回蹲坷,后面依靠系統(tǒng)的調(diào)度機(jī)制將緩存數(shù)據(jù)刷到磁盤中去,其順序是user buffer——> page cache——>disk蜕企。

除了上面談到的Force Log at Commit機(jī)制保證事務(wù)的持久性,實(shí)際上redo log的實(shí)現(xiàn)還要依賴于mini-transaction冠句。

Redo在InnoDB中是如何實(shí)現(xiàn)的?與mini-transaction的聯(lián)系幸乒?

Redo log的實(shí)現(xiàn)跟mini-transaction緊密相關(guān)懦底,mini-transaction是InnoDB內(nèi)部的機(jī)制,通過mini-transaction來保證并發(fā)事務(wù)操作下以及數(shù)據(jù)庫異常時(shí)數(shù)據(jù)頁中數(shù)據(jù)的一致性罕扎,但它不屬于事務(wù)聚唐。

為了使得mini-transaction保證數(shù)據(jù)頁數(shù)據(jù)的一致性,mini-transaction必須遵循以下三種協(xié)議

  • The FIX Rules
  • Write-Ahead Log
  • Force-log-at-commit

The FIX Rules

修改一個(gè)數(shù)據(jù)頁時(shí)需要獲得該頁的x-latch(排他鎖)腔召,獲取一個(gè)數(shù)據(jù)頁時(shí)需要該頁的s-latch(讀鎖或者稱為共享鎖) 或者是 x-latch杆查,持有該頁的鎖直到修改或訪問該頁的操作完成。

Write-Ahead Log

在持久化一個(gè)數(shù)據(jù)頁之前臀蛛,必須先將內(nèi)存中相應(yīng)的日志頁持久化亲桦。每個(gè)頁都有一個(gè)LSN(log sequence number),代表日志序列號浊仆,(LSN占用8字節(jié)客峭,單調(diào)遞增), 當(dāng)一個(gè)數(shù)據(jù)頁需要寫入到持久化設(shè)備之前,要求內(nèi)存中小于該頁LSN的日志先寫入持久化設(shè)備抡柿。

那為什么必須要先寫日志呢舔琅?可不可以不寫日志,直接將數(shù)據(jù)寫入磁盤洲劣?原則上是可以的备蚓,只不過會產(chǎn)生一些問題课蔬,數(shù)據(jù)修改會產(chǎn)生隨機(jī)IO,但日志是順序IO郊尝,append方式順序?qū)懚希且环N串行的方式,這樣才能充分利用磁盤的性能虚循。

Force-log-at-commit

在一個(gè)事務(wù)中可以修改多個(gè)頁同欠,Write-Ahead Log 可以保證單個(gè)數(shù)據(jù)頁的一致性,但是無法保證事務(wù)的持久性横缔,F(xiàn)orce-log-at-commit 要求當(dāng)一個(gè)事務(wù)提交時(shí)铺遂,其產(chǎn)生所有的mini-transaction 日志必須刷新到磁盤中,若日志刷新完成后茎刚,在緩沖池中的頁刷新到持久化存儲設(shè)備前數(shù)據(jù)庫發(fā)生了宕機(jī)襟锐,那么數(shù)據(jù)庫重啟時(shí),可以通過日志來保證數(shù)據(jù)的完整性膛锭。

redo log的寫入流程

123.png

上圖表示了redo log的寫入流程粮坞,每個(gè)mini-transaction對應(yīng)每一條DML操作,比如一條update語句初狰,其由一個(gè)mini-transaction來保證莫杈,對數(shù)據(jù)修改后,產(chǎn)生redo1奢入,首先將其寫入mini-transaction私有的Buffer中筝闹,update語句結(jié)束后,將redo1從私有Buffer拷貝到公有的Log Buffer中腥光。當(dāng)整個(gè)外部事務(wù)提交時(shí)关顷,將redo log buffer再刷入到redo log file中。

undo log

undo log的定義

undo log主要記錄數(shù)據(jù)的邏輯變化武福,為了在發(fā)生錯(cuò)誤時(shí)回滾之前的操作议双,需要將之前的操作都記錄下來,然后在發(fā)生錯(cuò)誤時(shí)才可以回滾捉片。

undo log的作用

undo是一種邏輯日志平痰,有兩個(gè)作用:

  • 事務(wù)回滾
  • MVCC

重點(diǎn)關(guān)注如何利用undo log進(jìn)行事務(wù)回滾。

undo日志界睁,只將數(shù)據(jù)庫邏輯地恢復(fù)到原來的樣子觉增,在回滾的時(shí)候,它實(shí)際上是做的相反的工作翻斟,比如一條INSERT 逾礁,對應(yīng)一條 DELETE,對于每個(gè)UPDATE,對應(yīng)一條相反的 UPDATE,將修改前的行放回去。通過undo log進(jìn)行事務(wù)回滾操作可以保障事務(wù)的原子性嘹履。

undo log的寫入時(shí)機(jī)

  • DML操作修改聚簇索引前腻扇,記錄undo log
  • 二級索引記錄的修改,不記錄undo log

需要注意的是砾嫉,undo log頁面的修改幼苛,同樣需要記錄redo日志。

undo log的存儲位置

在InnoDB存儲引擎中焕刮,undo log存儲在回滾段(Rollback Segment)中,每個(gè)回滾段記錄了1024個(gè)undo log segment舶沿,而在每個(gè)undo log segment段中進(jìn)行undo 頁的申請,在5.6以前配并,Rollback Segment是在共享表空間里的括荡,5.6.3之后,可通過 innodb_undo_tablespace設(shè)置undo存儲的位置溉旋。

undo的類型

在InnoDB存儲引擎中畸冲,undo log分為:

  • insert undo log
  • update undo log

insert undo log是指在insert 操作中產(chǎn)生的undo log,因?yàn)閕nsert操作的記錄观腊,只對事務(wù)本身可見邑闲,對其他事務(wù)不可見。故該undo log可以在事務(wù)提交后直接刪除梧油,不需要進(jìn)行purge操作苫耸。

而update undo log記錄的是對delete 和update操作產(chǎn)生的undo log,該undo log可能需要提供MVCC機(jī)制儡陨,因此不能再事務(wù)提交時(shí)就進(jìn)行刪除鲸阔。提交時(shí)放入undo log鏈表,等待purge線程進(jìn)行最后的刪除迄委。

補(bǔ)充:purge線程兩個(gè)主要作用是:清理undo頁和清除page里面帶有Delete_Bit標(biāo)識的數(shù)據(jù)行。在InnoDB中类少,事務(wù)中的Delete操作實(shí)際上并不是真正的刪除掉數(shù)據(jù)行叙身,而是一種Delete Mark操作,在記錄上標(biāo)識Delete_Bit硫狞,而不刪除記錄信轿。是一種"假刪除",只是做了個(gè)標(biāo)記,真正的刪除工作需要后臺purge線程去完成残吩。

undo log 是否是redo log的逆過程财忽?

undo log 是否是redo log的逆過程?其實(shí)從前文就可以得出答案了泣侮,undo log是邏輯日志即彪,對事務(wù)回滾時(shí),只是將數(shù)據(jù)庫邏輯地恢復(fù)到原來的樣子活尊,而redo log是物理日志隶校,記錄的是數(shù)據(jù)頁的物理變化漏益,顯然undo log不是redo log的逆過程。

redo & undo總結(jié)

下面是redo log + undo log的簡化過程深胳,便于理解兩種日志的過程:

假設(shè)有A绰疤、B兩個(gè)數(shù)據(jù),值分別為1,2.
1. 事務(wù)開始
2. 記錄A=1到undo log
3. 修改A=3
4. 記錄A=3到 redo log
5. 記錄B=2到 undo log
6. 修改B=4
7. 記錄B=4到redo log
8. 將redo log寫入磁盤
9. 事務(wù)提交

實(shí)際上舞终,在insert/update/delete操作中轻庆,redo和undo分別記錄的內(nèi)容都不一樣,量也不一樣敛劝。在InnoDB內(nèi)存中余爆,一般的順序如下:

  • 寫undo的redo
  • 寫undo
  • 修改數(shù)據(jù)頁
  • 寫Redo

參考:

https://segmentfault.com/a/1190000017888478
https://juejin.im/entry/5ba0a254e51d450e735e4a1f

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市攘蔽,隨后出現(xiàn)的幾起案子龙屉,更是在濱河造成了極大的恐慌,老刑警劉巖满俗,帶你破解...
    沈念sama閱讀 211,042評論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件转捕,死亡現(xiàn)場離奇詭異,居然都是意外死亡唆垃,警方通過查閱死者的電腦和手機(jī)五芝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評論 2 384
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來辕万,“玉大人枢步,你說我怎么就攤上這事〗ツ颍” “怎么了醉途?”我有些...
    開封第一講書人閱讀 156,674評論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長砖茸。 經(jīng)常有香客問我隘擎,道長,這世上最難降的妖魔是什么凉夯? 我笑而不...
    開封第一講書人閱讀 56,340評論 1 283
  • 正文 為了忘掉前任货葬,我火速辦了婚禮,結(jié)果婚禮上劲够,老公的妹妹穿的比我還像新娘震桶。我一直安慰自己,他們只是感情好征绎,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評論 5 384
  • 文/花漫 我一把揭開白布蹲姐。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪淤堵。 梳的紋絲不亂的頭發(fā)上寝衫,一...
    開封第一講書人閱讀 49,749評論 1 289
  • 那天,我揣著相機(jī)與錄音拐邪,去河邊找鬼慰毅。 笑死,一個(gè)胖子當(dāng)著我的面吹牛扎阶,可吹牛的內(nèi)容都是我干的汹胃。 我是一名探鬼主播,決...
    沈念sama閱讀 38,902評論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼东臀,長吁一口氣:“原來是場噩夢啊……” “哼着饥!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起惰赋,我...
    開封第一講書人閱讀 37,662評論 0 266
  • 序言:老撾萬榮一對情侶失蹤宰掉,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后赁濒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體轨奄,經(jīng)...
    沈念sama閱讀 44,110評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評論 2 325
  • 正文 我和宋清朗相戀三年拒炎,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挪拟。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,577評論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡击你,死狀恐怖玉组,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情丁侄,我是刑警寧澤惯雳,帶...
    沈念sama閱讀 34,258評論 4 328
  • 正文 年R本政府宣布,位于F島的核電站鸿摇,受9級特大地震影響吨凑,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜户辱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望糙臼。 院中可真熱鬧庐镐,春花似錦、人聲如沸变逃。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至名眉,卻和暖如春粟矿,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背损拢。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評論 1 264
  • 我被黑心中介騙來泰國打工陌粹, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人福压。 一個(gè)月前我還...
    沈念sama閱讀 46,271評論 2 360
  • 正文 我出身青樓掏秩,卻偏偏與公主長得像,于是被迫代替她去往敵國和親荆姆。 傳聞我的和親對象是個(gè)殘疾皇子蒙幻,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評論 2 348

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

  • 本文是介紹MySQL數(shù)據(jù)庫InnoDB存儲引擎重做日志漫游 00 – Undo Log Undo Log 是為了實(shí)...
    胖虎大哥閱讀 2,240評論 1 3
  • 我們都知道事務(wù)有4種特性:原子性、一致性胆筒、隔離性和持久性邮破,在事務(wù)中的操作,要么全部執(zhí)行仆救,要么全部不做抒和,這就是事務(wù)的...
    pjmike閱讀 31,793評論 5 36
  • 7.1 認(rèn)識事務(wù)7.1.1 概述事務(wù)可由一條非常簡單的SQL語句組成,也可以由一組復(fù)雜的SQL語句組成派桩。事務(wù)是訪問...
    正在加載更多閱讀 498評論 0 0
  • 1构诚、ACID 事務(wù)是數(shù)據(jù)庫區(qū)別于文件系統(tǒng)的重要特性之一。 InnoDB的事務(wù)完全符合ACID特性铆惑。 原子性(Ato...
    冰河winner閱讀 683評論 0 2
  • 一范嘱、事務(wù)概述 我們可以將事務(wù)理解為一組sql語句的集合。事務(wù)可以只包含一條sql员魏,也可以包含多條sql丑蛤,事務(wù)中所有...
    國球乒乓閱讀 358評論 0 0