Mysql中的Redo Log解析(二)
- 2019 年 11 月 6 日
- 筆記
昨天介紹了redo log的概念,關於redo log的寫入方法沒有很詳細的講解,今天接著說一下。
mysql中的redo log解析(二)
01
redo log寫入方法詳解
昨天我們說到了mtr的概念,也就是最小事務組,當我們向一個表裏面插入一條記錄的時候,這個操作就是一個最小事務組,因為它不可以再被分割。只有插入成功和插入失敗兩種結果。這個mtr操作中,包含了很多條redo log,例如需要記錄數據頁分裂的redo log,記錄剩餘數據空閑空間的redo log,記錄數據也內鏈表指針改變的redo log,在Innodb存儲引擎中,這些記錄都會被存在一個專門放置redo log的數據頁裏面,這個redo log的數據頁和我們之前立即的不同,它的大小只有512個位元組,而不是16k,我們用block來代替這種512位元組的數據頁,16k的數據頁使用page來代替,這個512位元組的數據頁包含三個部分,分別是header ,body 和tailer,header包含12個位元組,body包含496個位元組,tailer包含4個位元組,其中,header和tailer包含的是一些頭信息和尾信息,我們暫時不用關注。畫成圖就是:
![](https://ask.qcloudimg.com/http-save/6430377/8k94lw2lem.png)
上圖是單個redo log的數據頁,我們知道,申請buffer pool的時候,我們說過,buffer pool中也包含redo log buffer,顧名思義,也就是說,redo log也是不能直接寫在磁盤上了,而是寫在redo log的緩衝區中,我們用下面的圖來代替一下redo log buffer的樣子,這樣大家有一個直觀的概念:
![](https://ask.qcloudimg.com/http-save/6430377/zlkix9ew4h.png)
這個redo log buffer的大小值可以使用innodb_log_buffer_size來表示,默認值是16M.
當有redo log保存在redo log buffer中的時候,redo log buffer的樣子將會變成:
![](https://ask.qcloudimg.com/http-save/6430377/79046lupfv.png)
圖中,粉色部分,就是寫入了redo log的部分。黃色部分是空的redo log的部分。
這裡需要注意的是,粉色部分是一個一個mtr的redo日誌堆積而成的,這些日誌在buffer pool中的順序是隨機的,加入有兩個mtr ,分別是mtr1和mtr2,那麼這兩個mtr的redo log是交替保存在redo log buffer中的。
02
刷盤操作
log buffer的大小是有限的,當mtr結束的時候,會將redo log保存在redo log buffer中,在下面幾種情況下,innodb會將redo log buffer中的內容刷入到磁盤裏面:
1、log buffer空間不足時
一般情況下,當redo log 佔用了redo log buffer的一半時,將會進行redo log 的刷盤操作
2、事務提交時。
事務一旦提交,事務所做的修改將會保存在buffer pool中,那麼要想保證事務的一致性,就必須將redo log刷入到磁盤裏面。
3、後台線程每一秒都進行一次刷盤操作
4、正常關閉MySQL服務的時候,會進行刷盤。
剛才我們說了,redo log是保存在一個一個的block數據頁裏面的,然後這些block會被刷入到磁盤中,也就是我們的ib_logfile文件中,這裡有一點需要注意,就是ib_logfile中的前4個block是保存了一些通用信息,所以ib_logfile從第2048個位元組開始,其中的內容才是redo log,化成圖就是:
![](https://ask.qcloudimg.com/http-save/6430377/y8iccqz6gd.png)
前4個數據頁裏面保存的是一些通用信息,後面的數據頁保存的才是redo log的信息,畫成圖就是:
![](https://ask.qcloudimg.com/http-save/6430377/gh070m0kiv.png)
到這裡,我們已經知道了ib_logfile的大概內容,當MySQL服務啟動的時候,隨着時間的推移,將會發生很多變更動作,每一個動作將會生成不同的redo log,這些redo log 將會從block的body處開始往後連續的寫,寫滿一個block,然後再去寫下一個。例如上圖中,ib_logfile0中redo log寫了2個block,其中第二個block寫了一半,為了標記目前block寫到的位置,innodb中使用一個叫做LSN(Log Sequence Number)的全局量來保存這個位置,翻譯過來就是日誌序列。這個日誌序列是用來描述當前內存中的日誌寫到了redo log buffer的哪個位置。
前面我們說過,redo log buffer中不可能一直存儲redo log ,一定是有一個redo log的刷盤動作的,我們用另外一個參數:buf_next_to_write來表示下一個將要被刷盤的位置,這樣,畫出ib_logfile的圖來看,就是:
![](https://ask.qcloudimg.com/http-save/6430377/7mwxe12nsn.png)
途中,綠色部分是已經刷到磁盤的block數據頁,而粉色部分是在內存還沒有刷到磁盤中的redo log頁,橙色部分是還沒有被使用的block 數據頁。
在MySQL服務剛開始啟動的時候,buf_next_to_write和lsn是在同一個位置的,隨着時間的推移,redo日誌不斷的寫入block,lsn的位置超過buf_next_to_write的位置,二者拉開了一點差距。
到這裡,我們已經理解了redo log寫入磁盤的方法,下篇文章中將會引入checkpoint的概念,來講述redo log是如何保證一致性的。今天的內容就先到這裡吧。