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

白日夢感覺作為研發同學的你可能真的沒必要了解摸清楚關於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機制嗎?

參考:

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

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

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

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

//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,耗子尾汁! (已發布)

文章公號 首發!連載中!關注微信公號回復:「抽獎」 還可參加抽📖活動

Tags: