談談傳說中的redo log是什麼?有啥用?

賜我白日夢發表於2020-12-07

白日夢感覺作為研發同學的你可能真的沒必要了解摸清楚關於redo log的這些機制。專注於寫SQL完全能hold住日常的工作。

但是呢,感覺最好還是要了解一下,因為一般面試官都知道redo log是咋回事,其次是大家茶前飯後嘮嗑時也能多少能插幾句嘴

文章公號 首發!連載中!關注微信公號回覆:“抽獎” 還可參加抽?活動

一、引出 redo log 的作用

繼續我們的MySQL專題。首先回顧一下前面白日夢同你分享過的知識點。

前面我們一起學習了MySQL undo log相關的知識點,看下面這張腦圖:

磁碟上的資料檔案叫表空間檔案,表空間有挺多的,比如系統表空間、undo log 表空間、你也可以讓create出來的每張table都有自己單獨的表空間。總之MySQL會將表空間資料頁通過磁碟IO載入進快取頁中。

SQL執行器會執行你傳送給MySQL的SQL語句,MySQL為了提高的效能,對於增、刪、改這種操作都是在記憶體中完成的,所謂的記憶體就是上圖中BufferPool。比如上圖中的SQL執行器執行了一條update xxx where id = 1語句,然後這個id = 1資料行所在的資料頁就會被你修改成髒資料頁。

此外MySQL還有專門的後臺執行緒等其他機制負責將髒資料頁重新整理同步回磁碟。


二、思考一個問題:

你可以結合上圖然後想一下:萬一髒頁還沒來得及重新整理到磁碟中,MySQL就掛了,怎麼辦呢?

對於業務程式碼來說,方才執行的事務是OK的,甚至前端都接受到了請求成功的響應。那結果修改的資料沒同步回磁碟,MySQL當機了會不會導致真實資料和邏輯上的資料不一致呢?

其實不會的!

MySQL使用redo log解決了這個問題,redo故名思義:重做。

當發生事務(增、刪、改)時會導致快取頁變成髒頁,於此同時MySQL會將事務涉及到的:對 XXX表空間中的XXX資料頁XXX偏移量的地方做了XXX更新。

所以MySQL意外當機重啟也沒關係。只要在重啟時解析redo log中的事務然後重放一遍。將Buffer Pool中的快取頁重做成髒頁。後續再在合適的時機將該髒頁刷入磁碟即可。

於是對於業務方來說,everything is ok!

redo log側重於重做!redo log中記錄的是物理層面的資料頁、偏移量。應對的問題是:MySQL異常當機後,如何將沒來得及提交的事物資料重做出來。

而後面文章中和大家分享的bin log中記錄了你對XXX表條件為XXX處的資料作了什麼修改,這是些都是邏輯上的概念。


三、redo log block

首先你得知道,redo並不是一條條直接寫入磁碟中去的!

在MySQL的設定中,redolog是按塊,一塊一塊的寫入到磁碟中去的。

你可以類比一下資料是按頁為單位來組織的,就更容易理解為啥redo log 要按照block來組織redo。

本質上就是兩個字:優化

log block長成下面這這樣:分成Header、Body、Trailer三部分 總共512位元組。而且是覆蓋寫入。

我粗略解讀一下這幅腦圖。

首先既然MySQL會寫redo log,說明你的sql會對快取頁造成修改,也就意味著會走MySQL設定的事物那一套機制。既然是MySQL事物,大概率就是一組增、刪、改。如果每個增、刪、改都會有一個對應的redo log的話,那也就是說你的事物會產生好多redolog。這些redo會先被持續不斷的寫入到log block中,同一個事物產生的redo log會被標記為一個redo log group。


四、redo log buffer

瞭解redo log block之後,白日夢還要跟你介紹一下 redo log buffer。

這個redo log buffer 中會劃分出多個rodo log block。redo log buffer 佔用一塊連續的記憶體空間,預設大小16MB。且MySQL允許我們通過引數innodb_log_buffer_size動態的調整它。增大它的大小可以讓MySQL處理大事物是不必寫入磁碟。進而提升寫IO效能。

引入rodo log buffer之後,就可以勾勒出這樣一副腦圖。

如圖,產生的redo log 先寫入redo log block。然後redo log block其實就在redo log buffer 中。

看到這裡不知道你有沒有想到這樣一個問題:redo log buffer再怎麼神奇畢竟也是僅僅在記憶體中,此時萬一MySQL當機了怎麼辦?redolog-buffer中的資料丟失了怎麼辦?畢竟沒有寫到磁碟上,MySQL重啟後100%沒辦法將其恢復出來。

其實你並不用擔心這種情況!

因為在MySQL的設定中,當你要Commit事務時,redolog才會持久化進磁碟,既然你沒有commit,碰巧MySQL又當機了。那讓MySQL正常重啟就好了啊,反正你沒有commit,MySQL也也沒有必要幫你恢復什麼。

那 redo log buffer 何時寫入磁碟呢?

  1. 事物提交時把它對應的那些redo log寫入到磁碟中去(這個動作可由相關引數控制,下文會說)
  2. 當redo log buffer 使用量達到了引數innndb_log_buffer_size的一半時,會觸發落盤。
  3. 會有一個後臺執行緒,每隔1秒就會將redo log block重新整理到磁碟檔案中去。
  4. MySQL關閉時也會將其落盤。

五、redo log的刷盤時機

承接上面描述的場景:事務提交時,率先將redo log持久化進磁碟。

那你如何控制MySQL,讓MySQL在Commit事務時率先將redo log持久化呢?

MySQL提供了引數innodb_flush_log_at_trx_commit

該引數有幾個選項:0、1、2

  • 想要保證ACID四大特性推薦設定為1:表示當你commit時,MySQL必須將rodolog-buffer中的資料重新整理進磁碟中。確保只要commit是成功的,磁碟上就得有對應的rodolog日誌。這也是最安全的情況。

  • 設定為0:每秒寫一次日誌並將其重新整理到磁碟。

  • 設定為2:表示當你commit時,將redolog-buffer中的資料重新整理進OS Cache中,然後依託於作業系統每秒重新整理一次的機制將資料同步到磁碟中,也存在丟失的風險。


六、推薦引數

  • 始終設定 innodb_flush_log_at_trx_commit=1

  • 如果啟用了二進位制日誌記錄,請設定 sync_binlog=1

這也是大家常說的雙1設定。前者保證redolog的不丟失、後者保證了binlog的不丟失。

關於sync_binlog引數,計劃在第X、X、篇文章中分享binlog知識點的時候會再提及,歡迎關注!


七、redo log group

redo log group說的是:由N個大小相同的redo log組成一個redo log group。N的值預設為2。

你可以像下面這樣檢視你的MySQL的redo log group情況。

預設單個redo log檔案的大小是48MB。你也可以通過上圖中的innndb_log_files_size修改它。

日誌檔案的總大小(innodb_log_file_size* innodb_log_files_in_group)不能超過略小於512GB的最大值。

例如,一對255 GB的日誌檔案已達到限制,但沒有超過該限制。

同樣你可以像下面這樣檢視磁碟上的 redo log 檔案。它們的大小和上圖中的innodb_log_file_size相同。

innodb將log buffer中的redo log block重新整理到上圖中的logfile中時,以追加的方式迴圈寫入。也就是首先在ib_logfile0的尾部追加,寫滿後再寫ib_logfile1。當ib_logfile1寫滿時,情況一部分ib_logfile0接著追加寫。

redo log file的大小對innodb效能影響非常大。通常來說要設定的足夠大,大到可以讓MySQL支援1小時線上高峰流量的接入而不切換。但是設定的過大,資料恢復的時間比較長。設定過小導致迴圈切換redo log file。

能聊聊:日誌刷盤規則之 check point 和 LSN機制嗎?


參考:

https://dev.mysql.com/doc/refman/5.7/en/innodb-redo-log.html

https://dev.mysql.com/doc/refman/5.7/en/replication-solutions-unexpected-replica-halt.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-init-startup-configuration.html

https://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_flush_log_at_trx_commit

https://dev.mysql.com/doc/refman/5.7/en/innodb-init-startup-configuration.html


推薦閱讀

  1. 大家常說的基數是什麼?(已釋出)
  2. 講講什麼是慢查!如何監控?如何排查?(已釋出)
  3. 對NotNull欄位插入Null值有啥現象?(已釋出)
  4. 能談談 date、datetime、time、timestamp、year的區別嗎?(已釋出)
  5. 瞭解資料庫的查詢快取和BufferPool嗎?談談看!(已釋出)
  6. 你知道資料庫緩衝池中的LRU-List嗎?(已釋出)
  7. 談談資料庫緩衝池中的Free-List?(已釋出)
  8. 談談資料庫緩衝池中的Flush-List?(已釋出)
  9. 瞭解髒頁刷回磁碟的時機嗎?(已釋出)
  10. 用十一張圖講清楚,當你CRUD時BufferPool中發生了什麼!以及BufferPool的優化!(已釋出)
  11. 聽說過表空間沒?什麼是表空間?什麼是資料表?(已釋出)
  12. 談談MySQL的:資料區、資料段、資料頁、資料頁究竟長什麼樣?瞭解資料頁分裂嗎?談談看!(已釋出)
  13. 談談MySQL的行記錄是什麼?長啥樣?(已釋出)
  14. 瞭解MySQL的行溢位機制嗎?(已釋出)
  15. 說說fsync這個系統呼叫吧! (已釋出)
  16. 簡述undo log、truncate、以及undo log如何幫你回滾事物! (已釋出)
  17. 我勸!這位年輕人不講MVCC,耗子尾汁! (已釋出)


文章公號 首發!連載中!關注微信公號回覆:“抽獎” 還可參加抽?活動

相關文章