[轉]一文帶你看懂binlog和redo log

https://www.jianshu.com/p/907f9002442e

一文帶你看懂binlog和redo log

 

在介紹binlog和redolog之前,有必要先簡單介紹一下MySQL的邏輯架構。總體上來說,MySQL可以分爲server層和engine層兩部分,如下圖所示:

image

其中server層包括連接池、查詢緩存、分析器、優化器等部分,MySQL的大多數核心服務都在這一層,而engine層就是其插件式的存儲引擎,主要負責數據的存儲和讀取。

1.binlog

1.1binlog作用

我們今天要講的binlog就是server層產生的日誌,因此你知道,不管你使用的是哪一種存儲引擎,都會產生binlog。那問題來了,binlog有什麼用呢?

要知道它能「做什麼」,需要先知道它「是什麼」。簡單來說,binlog其實就是記錄了MySQL對數據庫執行更改的所有操作,因此很顯然,它可以用來做數據歸檔和數據恢復。

1.2binlog格式

在MySQL5.1之前,所有的binlog都是基於SQL語句級別的。但是應用這種格式的binlog進行數據恢復時,如果SQL語句帶有rand或uuid等函數,可能導致恢復出來的數據與原始數據不一致。因此從5.1版本開始,MySQL引入了binlog_format參數,該參數有三種可選值:statement、row和mixed:

  • statement就是之前的格式,基於SQL語句來記錄
  • row記錄的則是行的更改情況,可以避免之前提到的數據不一致的問題
  • 但是row格式有一個不好的地方就是當修改的行數很多時,生成的binlog佔用很大的空間,佔用大量空間的同時還會耗費大量IO資源,因此MySQL又提供了一種折中的方案——mixed。在mixed模式下,MySQL默認仍然採用statement格式進行記錄,但是一旦它判斷可能會有數據不一致的情況發生,則會採用row格式來記錄

我們可以通過這條語句來查看MySQL當前的binlog格式:

image

1.3binlog內容 —— statement格式

爲了查看binlog的具體內容,我們先創建一張表並對它進行初始化:

CREATE TABLE `t` (
  `id` int(10) NOT NULL auto_increment,
  `a` int(10) DEFAULT NULL,
  `created_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB;

insert into t values(null, 1,'2019-05-01');
insert into t values(null, 2,'2019-05-02');
insert into t values(null, 3,'2019-05-03');

查看當前binlog文件列表:

show master logs;

image

查看當前正在寫入的binlog文件:

show master status;

image

查看binlog文件內容:

show binlog events in 'mysql-bin.000006';

image

可以看到,我們執行的insert語句被包裹在一個事務當中,同時binlog原原本本記錄了我們的SQL語句。除此之外,我們還發現了另外一些東西:

  • 第一行的 SET@@SESSION.GTID_NEXT='ANONYMOUS'主要用於在主備複製時,將主庫的gtid集合同步到備庫
  • 第三行的INSERT_ID=3表示插入該行時的自增id=3
  • 第四行在我們的原始SQL語句之前的多了一句use test;這可以保證我們的SQL語句只會在test庫執行
  • 第五行 COMMIT/* xid=1557 */中的xid有兩個作用:其一:通過有無xid可以判斷一個事務的binlog是否完整;其二:redo log中也有xid,通過這個字段可以將binlog和redo log關聯起來

1.4binlog內容 —— row格式

執行以下語句將binlog格式切換爲row,看看row格式下的binlog有何不同:

set session binlog_format = 'row';

插入一條新數據:

insert into t values (null, 4, '2019-05-04');

查看binlog如下:

image

可以發現,變化在於第3行和第4行,Intvar和Query兩個事件變成了Tablemap和Writerows。但是從這些信息中我們只能知道該事務對錶test.t做了插入操作,確並不知道插入的具體數據是什麼。

還好我們有mysqlbinlog工具,藉助它我們可以一窺究竟。

這裏有一點需要說明的是,mysqlbinlog不是MySQL數據庫的語法,而只是客戶端提供的一個工具,因此不需要登錄數據庫!!!不需要!!!說來慚愧,這個問題困擾了我好久,怎麼就一直提示我語法錯誤呢?o(╯□╰)o

image

另外執行mysqlbinlog命令必須指定binlog文件的具體路徑,筆者使用的是5.7版本,在該版本中,binlog存儲路徑的默認配置爲log-bin=mysql-bin。可是mysql-bin具體哪個路徑呢?這個也困擾了我一段時間,其實很簡單,find一下就知道了。

image

好,現在切到該目錄下執行命令,重點關注紅框中的內容。不難發現,與statement模式記錄完整SQL語句不通,在row模式下,binlog記錄的表中每個字段的值。

image

1.5binlog內容 —— mixed格式

前面提到,在mixed模式下,MySQL默認仍然採用statement格式進行記錄,但是一旦它判斷可能會有數據不一致的情況發生,則會採用row格式來記錄,大家可以自行進行試驗查看。

2.redo log

在binlog日誌文件目錄下,我們還發現了這兩個文件:

image

事實上這就是我們接下來要講的redo log,也就是重做日誌,它是InnoDB引擎特有的,記錄了InnoDB引擎下的事務日誌。

2.1redo log作用

同樣,我們首先要搞明白的是,已經有binlog了,爲什麼還需要redo log。

因爲兩者分工不同。binlog主要用來做數據歸檔,但是它並不具備崩潰恢復的能力,也就是說如果你的系統突然崩潰,重啓後可能會有部分數據丟失,而redo log的存在則可以完美解決這個問題。

2.2redo log構成

默認情況下,每個InnoDB引擎至少有一個重做日誌組,每個組下至少有兩個重做日誌文件,例如上文提到的iblogfile0和iblogfile1。重做日誌組中的每個日誌文件大小一致且循環寫入,也就是說先寫iblogfile0,寫滿了之後寫iblogfile1,一旦iblogfile1也寫滿了,則繼續寫iblogfile0。顯然,如果沒有任何保護措施,這種機制會導致之前寫入ib_logfile0的內容被覆蓋。因此一旦redo log寫滿,MySQL將不得不停下所有更新操作來刷髒頁,這也是我們在爲什麼你的SQL執行很慢中提到的一點。

2.3redo log內容

binlog有三種格式,並且每種格式我們都可以具體查看其內容,那麼redo log的內容怎麼查看呢?

目前好像並沒有什麼辦法可以以人類可以理解的方式查看redo log,原因在於與binlog記錄的是邏輯日誌不同,redo log記錄的是對數據頁更改的物理日誌,比如類似「將第8頁、第1行、第6個位置改成666」這種,下圖是我用hexdump查看ib_logfile0的結果,其中紅框標出來的部分是插入一條數據後新增的日誌文件。

image

3.總結

本文從幾個方面簡單介紹了一下binlog和redo log,現在簡單總結一下兩者的不同點:

  • 功能不同,binlog主要用於歸檔,而redo log主要用於崩潰恢復

  • 內容不同,binlog是邏輯日誌,而redo log是物理日誌

  • 寫入時機不同,binlog是server層記錄的,所有存儲引擎可共享,而redo log是InnoDB引擎特有的

  • 寫入方式不同,binlog容量無限,追加寫入,而redo log容量有限,循環寫入

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章