redo log保證事務的持久性,undo log用來幫助事務回滾及MVCC的功能。html
事務提交時,先寫重作日誌再修改頁;當因爲發生宕機而致使數據丟失時,就能夠經過重作日誌來完成數據的恢復。數據庫
重作日誌文件: 在默認狀況,InnoDB存儲引擎的數據目錄下會有兩個名爲ib_logfile1和ib_logfile2的文件。每一個InnoDB存儲引擎至少有1個重作日誌文件組(group),每一個文件組下至少有2個重作日誌文件。緩存
下面圖一,很好說明重作日誌組以循環寫入方式運行,InnoDB存儲引擎先寫ib_logfile1,當達到文件最後時,會切換至重作日誌文件ib_logfile2.數據結構
而圖2,增長一個OS Buffer,有助於理解fsync過程。併發
關於log group,稱爲重作日誌組,是一個邏輯上的概念。InnoDB存儲引擎實際只有一個log group。
mvc
log group中第一個redo log file,其前2KB部分保存4個512字節大小塊:異步
下面三種狀況刷新:函數
補充上述三種狀況第二種,觸發寫磁盤過程由參數innodb_flush_log_at_trx_commit控制,表示提交(commit)操做時,處理重作日誌的方式。性能
參數innodb_flush_log_at_trx_commit有效值有0、一、2spa
0,當數據庫發生宕機時,部分日誌未刷新到磁盤,所以會丟失最後一段時間的事務。
2,當操做系統宕機時,重啓數據庫後會丟失未從文件系統緩存刷新到重作日誌文件那部分事務。
下圖有助於理解
在InnoDB存儲引擎中,重作日誌都是以512字節進行存儲的。意味着重作日誌緩存、重作日誌文件都是以塊(block)的方式進行保存的,每塊512字節。
重作日誌頭12字節,重作日誌尾8字節,故每一個重作日誌塊實際能夠存儲492字節。
redo log是基於頁的格式來記錄的。默認狀況下,innodb的頁大小是16KB(由 innodb_page_size變量控制),一個頁內能夠存放很是多的log block(每一個512字節),而log block中記錄的又是數據頁的變化。
log body的格式分爲4部分:
以下圖,分別是insert和delete大體的記錄方式。
下面LSN(Log Sequence Number)表明checkpoint,當數據庫在LSN爲10000時發生宕機,恢復操做僅恢復LSN10000-LSN13000範圍內日誌
undo是邏輯日誌,只是將數據庫邏輯地恢復到原來的樣子;全部修改都被邏輯地取消了,可是數據結構和頁自己在回滾以後可能不大相同。
undo log有兩個做用:提供回滾和多個行版本控制(MVCC)。
InnoDB存儲引擎回滾時,對於每一個INSERT,會完成一個DELETE;對於每一個DELETE,會執行一個INSERT;對於每一個UPDATE,會執行一個相反的UPDATE,將修改前的行放回去。
MVCC: 當用戶讀取一行記錄時,若該記錄已經被其餘事務佔用,當前事務能夠經過undo讀取以前的行版本信息,以此實現非鎖定讀取。
innodb存儲引擎對undo的管理採用段的方式。rollback segment稱爲回滾段,每一個回滾段中有1024個undo log segment。
在之前老版本,只支持1個rollback segment,這樣就只能記錄1024個undo log segment。後來MySQL5.5能夠支持128個rollback segment,即支持128*1024個undo操做,還能夠經過變量 innodb_undo_logs (5.6版本之前該變量是 innodb_rollback_segments )自定義多少個rollback segment,默認值爲128。
undo log默認存放在共享表空間中。
當事務提交時,InnoDB存儲引擎會作如下兩件事:
當事務提交時,首先將undo log放入鏈表中,而後判斷undo頁的使用空間是否小於3/4,如果,則表示該undo頁能夠被重用,以後新的undo log記錄在當前undo log的後面
undo log分爲:
由於事務隔離性,insert undo log對其餘事務不可見,因此該undo log能夠在事務提交後直接刪除,不須要進行purge操做。
update undo log記錄的是對delete和update操做產生的undo log。該undo log可能須要提供MVCC機制,所以不能提交時就進行刪除
update分爲兩種狀況:
InnoDB purge時,會先從history列表找undo log,而後再從undo page中找undo log;能夠避免大量隨機讀取操做,從而提升purge效率。
MVCC其實就是在每一行記錄後面增長兩個隱藏列,記錄建立版本號和刪除版本號,而每個事務在啓動的時候,都有一個惟一的遞增的版本號。
MVCC只在REPEATABLE READ 和READ COMMITTED兩個隔離級別下工做。讀未提交不存在版本問題,序列化則對全部讀取行加鎖。
示例:
如插入一條記錄,事務id假設是1,則建立版本號也是1
id | name | create version | delete version |
---|---|---|---|
1 | test | 1 |
如事務2把name字段更新
update table set name = 'new test' where id = 1;
原來的記錄被標記刪除,刪除版本號爲2,並插入新記錄,建立版本號爲2
id | name | create version | delete version |
---|---|---|---|
1 | test | 1 | 2 |
1 | new test | 2 |
如事務3把記錄刪除
delete from table where id = 1;
id | name | create version | delete version |
---|---|---|---|
1 | test | 2 | 3 |
需知足如下兩個條件的記錄才能被事務查詢出來:
MVCC好處:減小鎖的爭用,提高性能
二進制文件(binary log)記錄了對MySQL數據庫執行更改的全部操做(不包含SELECT、SHOW等,由於對數據沒有修改)
二進制文件主要幾種做用:
MySQL 5.1開始引入binlog_format參數,該參數可設值有STATEMENT、ROW和MIX(三種模式優缺點可參考https://mp.weixin.qq.com/s/KB73550tKpNccW-WKxT7-A)
(二進制文件用來進行POINT-IN-TIME(PIT))的恢復及主從複製環境的創建。
若事務爲非只讀事務,則每次事務提交時須要進行一次fsync操做,以此保證重作日誌都已經寫入磁盤。但磁盤fsync性能有限,爲提升磁盤fsync效率,當前數據庫都提供group commit功能,即一次能夠刷新確保多個事務日誌被寫入文件。
對InnoDB group commit,進行兩階段操做:
InnoDB1.2前,開啓二進制文件,group commit功能失效問題:
開啓二進制文件後,其步驟以下:
1)當事務提交時,InnoDB存儲引擎進行prepare操做
2)MySQL數據庫上層寫入二進制文件
3)InnoDB將日誌寫入重作日誌文件
其中在保證MySQL數據庫上層二進制文件的寫入順序,和InnoDB事務提交順序一致,MySQL內部使用了prepare_commit_mutex鎖,從而步驟3)中a)步不能夠在其餘事務執行步驟b)時進行,從而致使roup commit功能失效。
解決方案即是BLGC(Binary Log Group Commit)
MySQL 5.6 BLGC實現方式分爲三個階段:
參考:
《MySQL技術內幕》
https://mp.weixin.qq.com/s/rNFy_qwnNWUvzjYznOXKJw
https://www.cnblogs.com/hapjin/archive/2019/09/28/11521506.html
https://mp.weixin.qq.com/s/E-iJRPt5YRdLUja8RwzZ3A