0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

MySQL日志之Undo log知識(shí)科普

OSC開(kāi)源社區(qū) ? 來(lái)源:OSCHINA 社區(qū) ? 作者: GreatSQL ? 2022-10-17 11:43 ? 次閱讀

什么是Undo Log?

如何理解Undo Log

Undo Log的功能

Undo Log的存儲(chǔ)結(jié)構(gòu)

Undo Log的工作原理

Undo Log的類型

Undo Log的生命周期

Undo Log的配置參數(shù)

參考文章

文章導(dǎo)讀:

c12f117e-4bc2-11ed-a3b6-dac502259ad0.png

什么是Undo Log?

Undo:意為撤銷(xiāo)或取消,以撤銷(xiāo)操作為目的,返回某個(gè)狀態(tài)的操作。

Undo Log:數(shù)據(jù)庫(kù)事務(wù)開(kāi)始之前,會(huì)將要修改的記錄放到Undo日志里,當(dāng)事務(wù)回滾時(shí)或者數(shù)據(jù)庫(kù)崩潰時(shí),可以利用UndoLog撤銷(xiāo)未提交事務(wù)對(duì)數(shù)據(jù)庫(kù)產(chǎn)生的影響。

Undo Log是事務(wù)原子性的保證。在事務(wù)中更新數(shù)據(jù)的前置操作其實(shí)是要先寫(xiě)入一個(gè)Undo Log

如何理解Undo Log

事務(wù)需要保證原子性,也就是事務(wù)中的操作要么全部完成,要么什么也不做。但有時(shí)候事務(wù)執(zhí)行到一半會(huì)出現(xiàn)一些情況,比如:

情況一:事務(wù)執(zhí)行過(guò)程中可能遇到各種錯(cuò)誤,比如服務(wù)器本身的錯(cuò)誤,操作系統(tǒng)錯(cuò)誤,甚至是突然斷電導(dǎo)致的錯(cuò)誤。

情況二:DBA可以在事務(wù)執(zhí)行過(guò)程中手動(dòng)輸入ROLLBACK語(yǔ)句結(jié)束當(dāng)前事務(wù)的執(zhí)行。以上情況出現(xiàn),我們需要把數(shù)據(jù)改回原先的樣子,這個(gè)過(guò)程稱之為回滾。

每當(dāng)我們要對(duì)一條記錄做改動(dòng)時(shí)(這里的改動(dòng)可以指INSERT、DELETE、UPDATE),都需要把回滾時(shí)所需的東西記下來(lái)。比如:

你插入一條記錄時(shí),至少要把這條記錄的主鍵值記下來(lái),之后回滾的時(shí)候只需要把這個(gè)主鍵值對(duì)應(yīng)的記錄刪掉就好了。(對(duì)于每個(gè)INSERT, InnoDB存儲(chǔ)引擎會(huì)完成一個(gè)DELETE)

你刪除了一條記錄,至少要把這條記錄中的內(nèi)容都記下來(lái),這樣之后回滾時(shí)再把由這些內(nèi)容組成的記錄插入到表中就好了。(對(duì)于每個(gè)DELETE,InnoDB存儲(chǔ)引擎會(huì)執(zhí)行一個(gè)INSERT)

你修改了一條記錄,至少要把修改這條記錄前的舊值都記錄下來(lái),這樣之后回滾時(shí)再把這條記錄更新為舊值就好了。(對(duì)于每個(gè)UPDATE,InnoDB存儲(chǔ)引擎會(huì)執(zhí)行一個(gè)相反的UPDATE,將修改前的行放回去)

MySQL把這些為了回滾而記錄的這些內(nèi)容稱之為撤銷(xiāo)日志或者回滾日志(即Undo Log)。注意,由于查詢操作(SELECT)并不會(huì)修改任何用戶記錄,所以在杳詢操作行時(shí),并不需要記錄相應(yīng)的Undo日志

此外,Undo Log會(huì)產(chǎn)生Redo Log,也就是Undo Log的產(chǎn)生會(huì)伴隨著Redo Log的產(chǎn)生,這是因?yàn)閁ndo Log也需要持久性的保護(hù)。

Undo Log的功能

提供數(shù)據(jù)回滾-原子性
當(dāng)事務(wù)回滾時(shí)或者數(shù)據(jù)庫(kù)崩潰時(shí),可以利用Undo Log來(lái)進(jìn)行數(shù)據(jù)回滾。

多版本并發(fā)控制(MVCC)-隔離性
即在InnoDB存儲(chǔ)引擎中MVCC的實(shí)現(xiàn)是通過(guò)Undo Log來(lái)完成。當(dāng)用戶讀取一行記錄時(shí),若該記錄已經(jīng)被其他事務(wù)占用,當(dāng)前事務(wù)可以通過(guò)Undo Log讀取之前的行版本信息,以此實(shí)現(xiàn)非鎖定讀取。

Undo Log的存儲(chǔ)結(jié)構(gòu)

回滾段與Undo頁(yè)

InnoDB對(duì)Undo Log的管理采用段的方式,也就是回滾段(rollback segment)。每個(gè)回滾段記錄了1024 個(gè)Undo Log segment,而在每個(gè)Undo Log segment段中進(jìn)行Undo頁(yè)的申請(qǐng)。

在InnoDB1.1版本之前(不包括1.1版本),只有一個(gè)rollback segment,因此支持同時(shí)在線的事務(wù)限制為1024。雖然對(duì)絕大多數(shù)的應(yīng)用來(lái)說(shuō)都已經(jīng)夠用。

從1.1版本開(kāi)始InnoDB支持最大128個(gè)rollback segment,故其支持同時(shí)在線的事務(wù)限制提高到了128*1024。

mysql>showvariableslike'innodb_undo_logs';
+------------------+-------+
|Variable_name|Value|
+------------------+-------+
|innodb_undo_logs|128|
+------------------+-------+

雖然InnoDB1.1版本支持了128個(gè)rollback segment,但是這些rollback segment都存儲(chǔ)于共享表空間ibdata中。從lnnoDB1.2版本開(kāi)始,可通過(guò)參數(shù)對(duì)rollback segment做進(jìn)一步的設(shè)置。這些參數(shù)包括:

innodb_undo_directory:設(shè)置rollback segment文件所在的路徑。這意味著rollback segment可以存放在共享表空間以外的位置,即可以設(shè)置為獨(dú)立表空間。該參數(shù)的默認(rèn)值為“./”,表示當(dāng)前InnoDB存儲(chǔ)引擎的目錄。

innodb_undo_logs:設(shè)置rollback segment的個(gè)數(shù),默認(rèn)值為128。在InnoDB1.2版本中,該參數(shù)用來(lái)替換之前版本的參數(shù)innodb_rollback_segments。

innodb_undo_tablespaces:設(shè)置構(gòu)成rollback segment文件的數(shù)量,這樣rollback segment可以較為平均地分布在多個(gè)文件中。設(shè)置該參數(shù)后,會(huì)在路徑innodb_undo_directory看到undo為前綴的文件,該文件就代表rollback segment文件。

回滾段與事務(wù)

1.每個(gè)事務(wù)只會(huì)使用一個(gè)回滾段(rollback segment),一個(gè)回滾段在同一時(shí)刻可能會(huì)服務(wù)于多個(gè)事務(wù)。

2.當(dāng)一個(gè)事務(wù)開(kāi)始的時(shí)候,會(huì)制定一個(gè)回滾段,在事務(wù)進(jìn)行的過(guò)程中,當(dāng)數(shù)據(jù)被修改時(shí),原始的數(shù)據(jù)會(huì)被復(fù)制到回滾段。

3.在回滾段中,事務(wù)會(huì)不斷填充盤(pán)區(qū),直到事務(wù)結(jié)束或所有的空間被用完。如果當(dāng)前的盤(pán)區(qū)不夠用,事務(wù)會(huì)在段中請(qǐng)求擴(kuò)展下一個(gè)盤(pán)區(qū),如果所有已分配的盤(pán)區(qū)都被用完,事務(wù)會(huì)覆蓋最初的盤(pán)區(qū)或者在回滾段允許的情況下擴(kuò)展新的盤(pán)區(qū)來(lái)使用。

4.回滾段存在于Undo表空間中,在數(shù)據(jù)庫(kù)中可以存在多個(gè)Undo表空間,但同一時(shí)刻只能使用一個(gè)Undo表空間。

5.當(dāng)事務(wù)提交時(shí),InnoDB存儲(chǔ)引擎會(huì)做以下兩件事情:
1.將Undo Log放入列表中,以供之后的purge(清洗、清除)操作
2.判斷Undo Log所在的頁(yè)是否可以重用(低于3/4可以重用),若可以分配給下個(gè)事務(wù)使用

回滾段中的數(shù)據(jù)分類

未提交的回滾數(shù)據(jù)(uncommitted undo information):該數(shù)據(jù)所關(guān)聯(lián)的事務(wù)并未提交,用于實(shí)現(xiàn)讀一致性,所以該數(shù)據(jù)不能被其他事務(wù)的數(shù)據(jù)覆蓋。

已經(jīng)提交但未過(guò)期的回滾數(shù)據(jù)(committed undo information):該數(shù)據(jù)關(guān)聯(lián)的事務(wù)已經(jīng)提交,但是仍受到undo retention參數(shù)的保持時(shí)間的影響。

事務(wù)已經(jīng)提交并過(guò)期的數(shù)據(jù)(expired undo information):事務(wù)已經(jīng)提交,而且數(shù)據(jù)保存時(shí)間已經(jīng)超過(guò)undo retention參數(shù)指定的時(shí)間,屬于已經(jīng)過(guò)期的數(shù)據(jù)。當(dāng)回滾段滿了之后,會(huì)優(yōu)先覆蓋"事務(wù)已經(jīng)提交并過(guò)期的數(shù)據(jù)"。

Undo頁(yè)的重用

當(dāng)我們開(kāi)啟一個(gè)事務(wù)需要寫(xiě)Undo log的時(shí)候,就得先去Undo Log segment中去找到一個(gè)空閑的位置,當(dāng)有空位的時(shí)候,就去申請(qǐng)Undo頁(yè),在這個(gè)申請(qǐng)到的Undo頁(yè)中進(jìn)行Undo Log的寫(xiě)入。我們知道MySQL默認(rèn)一頁(yè)的大小是16k。

為每一個(gè)事務(wù)分配一個(gè)頁(yè),是非常浪費(fèi)的(除非你的事務(wù)非常長(zhǎng)),假設(shè)你的應(yīng)用的TPS(每秒處理的事務(wù)數(shù)目)為1000,那么1s就需要1000個(gè)頁(yè),大概需要16M的存儲(chǔ),1分鐘大概需要1G的存儲(chǔ)。如果照這樣下去除非MySQL清理的非常勤快,否則隨著時(shí)間的推移,磁盤(pán)空間會(huì)增長(zhǎng)的非???,而且很多空間都是浪費(fèi)的。

于是Undo頁(yè)就被設(shè)計(jì)的可以重用了,當(dāng)事務(wù)提交時(shí),并不會(huì)立刻刪除Undo頁(yè)。因?yàn)橹赜?,所以這個(gè)Undo頁(yè)可能混雜著其他事務(wù)的Undo Log。Undo Log在commit后,會(huì)被放到一個(gè)鏈表中,然后判斷Undo頁(yè)的使用空間是否小于3/4,如果小于3/4的話,則表示當(dāng)前的Undo頁(yè)可以被重用,那么它就不會(huì)被回收,其他事務(wù)的Undo Log可以記錄在當(dāng)前Undo頁(yè)的后面。由于Undo Log是離散的,所以清理對(duì)應(yīng)的磁盤(pán)空間時(shí),效率不高。

Undo Log日志的存儲(chǔ)機(jī)制

c14e87a2-4bc2-11ed-a3b6-dac502259ad0.png如上圖,可以看到,Undo Log日志里面不僅存放著數(shù)據(jù)更新前的記錄,還記錄著RowID、事務(wù)ID、回滾指針。其中事務(wù)ID每次遞增,回滾指針第一次如果是INSERT語(yǔ)句的話,回滾指針為NULL,第二次UPDATE之后的Undo Log的回滾指針就會(huì)指向剛剛那一條Undo Log日志,以此類推,就會(huì)形成一條Undo Log的回滾鏈,方便找到該條記錄的歷史版本。

Undo Log的工作原理

在更新數(shù)據(jù)之前,MySQL會(huì)提前生成Undo Log日志,當(dāng)事務(wù)提交的時(shí)候,并不會(huì)立即刪除Undo Log,因?yàn)楹竺婵赡苄枰M(jìn)行回滾操作,要執(zhí)行回滾(ROLLBACK)操作時(shí),從緩存中讀取數(shù)據(jù)。Undo Log日志的刪除是通過(guò)通過(guò)后臺(tái)purge線程進(jìn)行回收處理的。c165e686-4bc2-11ed-a3b6-dac502259ad0.png

1、事務(wù)A執(zhí)行UPDATE操作,此時(shí)事務(wù)還沒(méi)提交,會(huì)將數(shù)據(jù)進(jìn)行備份到對(duì)應(yīng)的Undo Buffer,然后由Undo Buffer持久化到磁盤(pán)中的Undo Log文件中,此時(shí)Undo Log保存了未提交之前的操作日志,接著將操作的數(shù)據(jù),也就是test表的數(shù)據(jù)持久保存到InnoDB的數(shù)據(jù)文件IBD。

2、此時(shí)事務(wù)B進(jìn)行查詢操作,直接從Undo Buffer緩存中進(jìn)行讀取,這時(shí)事務(wù)A還沒(méi)提交事務(wù),如果要回滾(ROLLBACK)事務(wù),是不讀磁盤(pán)的,先直接從Undo Buffer緩存讀取。

Undo Log的類型

在InnoDB存儲(chǔ)引擎中,Undo Log分為:

insert Undo Log
insert Undo Log是指在insert操作中產(chǎn)生的Undo Log。因?yàn)閕nsert操作的記錄,只對(duì)事務(wù)本身可見(jiàn),對(duì)其他事務(wù)不可見(jiàn)(這是事務(wù)隔離性的要求),故該Undo Log可以在事務(wù)提交后直接刪除。不需要進(jìn)行purge操作。

update Undo Log
update Undo Log記錄的是對(duì)delete和update操作產(chǎn)生的Undo Log。該Undo Log可能需要提供MVCC機(jī)制,因此不能在事務(wù)提交時(shí)就進(jìn)行刪除。提交時(shí)放入U(xiǎn)ndo Log鏈表,等待purge線程進(jìn)行最后的刪除。

Undo Log的生命周期

簡(jiǎn)要生成過(guò)程
以下是Undo+Redo事務(wù)的簡(jiǎn)化過(guò)程:
假設(shè)有2個(gè)數(shù)值,分別為 A=1 和 B=2 ,然后將A修改為3,B修改為4

1.starttransaction;
2.記錄A=1到UndoLog;
3.updateA=3;
4.記錄A=3到RedoLog;
5.記錄B=2到UndoLog;
6.updateB=4;
7.記錄B=4到RedoLog;
8.將RedoLog刷新到磁盤(pán);
9.commit

在1-8步驟的任意一步系統(tǒng)宕機(jī),事務(wù)未提交,該事務(wù)就不會(huì)對(duì)磁盤(pán)上的數(shù)據(jù)做任何影響。

如果在8-9之間宕機(jī)。

Redo Log 進(jìn)行恢復(fù)

Undo Log 發(fā)現(xiàn)有事務(wù)沒(méi)完成進(jìn)行回滾。

若在9之后系統(tǒng)宕機(jī),內(nèi)存映射中變更的數(shù)據(jù)還來(lái)不及刷回磁盤(pán),那么系統(tǒng)恢復(fù)之后,可以根據(jù)Redo Log把數(shù)據(jù)刷回磁盤(pán)。

流程圖:c1b5ba9e-4bc2-11ed-a3b6-dac502259ad0.png

Undo Log的配置參數(shù)

innodb_max_undo_log_size:Undo日志文件的最大值,默認(rèn)1GB,初始化大小10M

innodb_undo_log_truncate:標(biāo)識(shí)是否開(kāi)啟自動(dòng)收縮Undo Log表空間的操作

innodb_undo_tablespaces:設(shè)置獨(dú)立表空間的個(gè)數(shù),默認(rèn)為0,標(biāo)識(shí)不開(kāi)啟獨(dú)立表空間,Undo日志保存在ibdata1中

innodb_undo_directory:Undo日志存儲(chǔ)的目錄位置innodb_undo_logs: 回滾的個(gè)數(shù) 默認(rèn)128

審核編輯:湯梓紅

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • MySQL
    +關(guān)注

    關(guān)注

    1

    文章

    794

    瀏覽量

    26359
  • 日志
    +關(guān)注

    關(guān)注

    0

    文章

    135

    瀏覽量

    10618

原文標(biāo)題:圖文結(jié)合帶你搞定MySQL日志之Undo log(回滾日志)

文章出處:【微信號(hào):OSC開(kāi)源社區(qū),微信公眾號(hào):OSC開(kāi)源社區(qū)】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    MySQL的六個(gè)日志類型

    MySQL日志管理
    發(fā)表于 04-24 16:57

    Windows上MySQL配置log_bin后無(wú)法啟動(dòng)mysql服務(wù)怎么辦

    Windows上MySQL(zip壓縮版)配置log_bin后無(wú)法啟動(dòng)mysql服務(wù)
    發(fā)表于 05-22 07:40

    logcat如何查看Andriod log系統(tǒng)日志?

    logcat會(huì)輸出系統(tǒng)哪些信息呢?如何學(xué)習(xí)logcat命令?logcat如何查看Andriod log系統(tǒng)日志?如何查看Andriod log系統(tǒng)日志?
    發(fā)表于 03-03 06:15

    MySQL5新特性存儲(chǔ)過(guò)程

    MySQL5新特性存儲(chǔ)過(guò)程 MySQL5新特性存儲(chǔ)過(guò)程 MySQL5新特性存儲(chǔ)過(guò)程
    發(fā)表于 06-12 10:08 ?0次下載

    詳談MySQL數(shù)據(jù)庫(kù)的不同日志和源碼

    任何一種數(shù)據(jù)庫(kù),都會(huì)擁有各種各樣的日志,mysql也不例外。
    的頭像 發(fā)表于 07-02 16:52 ?2536次閱讀

    MySQL事務(wù)日志

    大家都清楚,日志MySQL 數(shù)據(jù)庫(kù)的重要組成部分,記錄著數(shù)據(jù)庫(kù)運(yùn)行期間各種狀態(tài)信息。MySQL 日志主要包括「錯(cuò)誤日志」、「查詢
    的頭像 發(fā)表于 11-14 09:58 ?1685次閱讀
    <b class='flag-5'>MySQL</b>事務(wù)<b class='flag-5'>日志</b>

    MySQL中的redo log是什么

    前言 說(shuō)到MySQL,有兩塊日志一定繞不開(kāi),一個(gè)是InnoDB存儲(chǔ)引擎的redo log(重做日志),另一個(gè)是MySQL Servce層的
    的頭像 發(fā)表于 09-14 09:40 ?1985次閱讀

    詳解MySQL三大日志的作用

    MySQL日志 主要包括錯(cuò)誤日志、查詢日志、慢查詢日志、事務(wù)日志、二進(jìn)制
    的頭像 發(fā)表于 07-22 14:44 ?1288次閱讀

    log4j日志框架分析

    og4j是Apache下的一款開(kāi)源的日志框架,能夠滿足我們?cè)陧?xiàng)目中對(duì)于日志記錄的需求。log4j提供了簡(jiǎn)單的API調(diào)用,強(qiáng)大的日志格式定義以及靈活的擴(kuò)展性。使用者可以自己定義Appen
    的頭像 發(fā)表于 02-28 14:32 ?1053次閱讀
    <b class='flag-5'>log</b>4j<b class='flag-5'>日志</b>框架分析

    針對(duì)大量log日志快速定位錯(cuò)誤地方

    用 grep 拿到的日志很少,我們需要查看附近的日志。我是這樣做的,首先: cat -n test.log | grep “關(guān)鍵詞” 得到關(guān)鍵日志的行號(hào)
    的頭像 發(fā)表于 04-21 09:22 ?655次閱讀

    C#上位機(jī)開(kāi)發(fā)(十三)使用Log4net添加日志記錄功能

    一、Log4net 官方網(wǎng)站: 。 下載二進(jìn)制dll庫(kù):包中提供了針對(duì)各個(gè)版本的dll庫(kù): 二、使用日志庫(kù) 1. 添加庫(kù) 復(fù)制對(duì)應(yīng)的庫(kù)文件到項(xiàng)目中: 2. 配置log4net 2.1. 創(chuàng)建配置文件添加后修改該文件設(shè)置:
    發(fā)表于 05-29 16:25 ?1次下載
    C#上位機(jī)開(kāi)發(fā)(十三)<b class='flag-5'>之</b>使用<b class='flag-5'>Log</b>4net添加<b class='flag-5'>日志</b>記錄功能

    服務(wù)器log日志大,掌握這些可正確快速定位錯(cuò)誤!

    針對(duì)大量log日志快速定位錯(cuò)誤地方
    的頭像 發(fā)表于 06-05 18:14 ?590次閱讀

    MySQL三種日志講解

    MySQL 日志包含了錯(cuò)誤日志、查詢日志、慢查詢日志、事務(wù)日志、二進(jìn)制
    的頭像 發(fā)表于 07-25 11:15 ?691次閱讀
    <b class='flag-5'>MySQL</b>三種<b class='flag-5'>日志</b>講解

    基于Rust的Log日志庫(kù)介紹

    Rust是一門(mén)系統(tǒng)級(jí)編程語(yǔ)言,因其安全性、高性能和并發(fā)性而備受歡迎。在Rust應(yīng)用程序中,日志記錄是一項(xiàng)非常重要的任務(wù),因?yàn)樗梢詭椭_(kāi)發(fā)人員了解應(yīng)用程序的運(yùn)行情況并解決問(wèn)題。Rust的Log庫(kù)提供
    的頭像 發(fā)表于 09-19 14:49 ?3272次閱讀

    nginx日志配置方法

    access_log用來(lái)定義日志級(jí)別,日志位置。
    的頭像 發(fā)表于 10-24 17:43 ?119次閱讀