MySQL 持久化保障機制-redo 日誌

咱們在 聊一聊 MySQL 中的事務及其實現原理 中提到了 redo 日誌,redo 日誌是用來保證 MySQL 持久化功能的,須要注意的是 redo 日誌是 InnoDB 引擎特有的功能。面試

爲何 InnoDB 引擎會引入 redo 日誌做爲中間層來保證 MySQL 持久化,而不是直接持久化到磁盤?咱們先來看看《MySQL實戰45講》中提到的一個故事。redis

在《孔乙己》這篇文章,酒店掌櫃有一個粉板,專門用來記錄客人的賒帳記錄。若是賒帳的人很少,那麼他能夠把顧客名和帳目寫在板上。但若是賒帳的人多了,粉板總會有記不下的時候,這個時候掌櫃必定還有一個專門記錄賒帳的帳本。數據庫

若是有人要賒帳或者還帳的話,掌櫃通常有兩種作法:緩存

  • 一種作法是直接把帳本翻出來,把此次賒的帳加上去或者扣除掉;
  • 另外一種作法是先在粉板上記下此次的帳,等打烊之後再把帳本翻出來覈算。

在生意紅火櫃檯很忙時,掌櫃必定會選擇後者,由於前者操做實在是太麻煩了。首先,你得找到這我的的賒帳總額那條記錄。你想一想,密密麻麻幾十頁,掌櫃要找到那個名字,可能還得帶上老花鏡慢慢找,找到以後再拿出算盤計算,最後再將結果寫回到帳本上。服務器

這整個過程想一想都麻煩。相比之下,仍是先在粉板上記一下方便。你想一想,若是掌櫃沒有粉板的幫助,每次記帳都得翻帳本,效率是否是低得讓人難以忍受?微信

一樣,在 MySQL 裏也有這個問題,磁盤就相對於帳本,若是每一次的更新操做都須要寫進磁盤,而後磁盤也要找到對應的那條記錄,而後再更新,整個過程 IO 成本、查找成本都很高異步

爲了解決這個問題,MySQL 的設計者就用了相似酒店掌櫃粉板的思路來提高更新效率,redo 日誌跟酒店粉板同樣,用來臨時存儲,承擔一箇中轉的角色post

具體來講,當有一條記錄須要更新的時候,InnoDB 引擎就會先把記錄寫到 redo log(粉板)裏面,並更新內存,這個時候更新就算完成了。同時,InnoDB 引擎會在適當的時候,將這個操做記錄更新到磁盤裏面,而這個更新每每是在系統比較空閒的時候作,這就像打烊之後掌櫃作的事學習

經過上面的這個故事你能夠理解爲何須要引入 redo 日誌,對 redo 日誌有必定的瞭解,下面咱們就來正式介紹 redo 日誌,先從 redo 日誌的結構開始:spa

redo 日誌通用結構

上面是 redo 日誌的通用結構,redo 日誌記錄的是每一個頁面(page)更改物理狀況,因此 redo 日誌總體來講是比較小的,存儲的信息很少,簡單的介紹一下這幾個字段的意思:

  • type:該條redo日誌的類型。
  • space ID:表空間ID。
  • page number:頁號。
  • data:該條redo日誌的具體內容。

redo 日誌並不是這麼簡單,它很是的複雜,可是咱們不須要對它庖丁解牛,由於它確實對咱們來講沒啥用,咱們只要記住 redo 日誌會把事務在執行過程當中對數據庫所作的全部修改都記錄下來,在以後系統崩潰重啓後能夠把事務所作的任何修改都恢復出來

在事務提交時將全部修改過的內存中的頁面刷新到磁盤中相比,只將該事務執行過程當中產生的 redo 日誌刷新到磁盤的好處以下:

  • redo日誌佔用的空間很是小:存儲表空間ID、頁號、偏移量以及須要更新的值所需的存儲空間是很小的
  • redo日誌是順序寫入磁盤的:在執行事務的過程當中,每執行一條語句,就可能產生若干條redo日誌,這些日誌是按照產生的順序寫入磁盤的,也就是使用順序IO。

redo 日誌工做原理

redo 日誌是循環寫入的,由於 InnoDB 的 redo log 是固定大小的,好比能夠配置爲一組 4 個文件,每一個文件的大小是 1GB,那麼這塊「粉板」總共就能夠記錄 4GB 的操做。從頭開始寫,寫到末尾就又回到開頭循環寫,以下面這個圖所示:

redo 日誌

write pos 是當前記錄的位置,一邊寫一邊後移,寫到第 3 號文件末尾後就回到 0 號文件開頭。checkpoint 是當前要擦除的位置,也是日後推移而且循環的,擦除記錄前要把記錄更新到數據文件。

write pos 和 checkpoint 之間的是「粉板」上還空着的部分,能夠用來記錄新的操做。若是 write pos 追上 checkpoint,表示「粉板」滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把 checkpoint 推動一下。

這大概就是 redo 日誌的工做原理,你就把它想象成一塊黑板就行了。

redo日誌緩衝區

redo 日誌並非直接寫入磁盤的,而是先寫入到緩存區,咱們把這個緩衝區叫作 redo日誌緩衝區。在服務器啓動時就向操做系統申請了一大片稱之爲 redo log buffer 的連續內存空間,咱們也能夠簡稱爲log buffer。這片內存空間被劃分紅若干個連續的 redo log block,以下圖所示:

redo日誌緩衝區

在 MySQL Server 5.7 下 redo日誌緩衝區的大小默認爲 1M,咱們能夠經過 innodb_log_buffer_size 參數來設置 redo 日誌緩衝區的大小。

向 log buffer 中寫入 redo 日誌的過程是順序的,也就是先往前邊的 block中寫,當該 block 的空閒空間用完以後再往下一個 block 中寫。

先寫入緩衝區再寫磁盤,就會碰到一個問題,這個問題在 redis AOF 持久化方式時也遇到過,就是緩衝區和磁盤之間的數據如何同步

在 MySQL 的配置文件中提供了 innodb_flush_log_at_trx_commit 參數,這個能夠用來控制緩衝區和磁盤之間的數據如何同步,這裏有 0、一、2 三個選項,在我裝的 MySQL 下默認的是 1,簡單介紹一下這三個選項的區別:

  • 0:表示當提交事務時,並不將緩衝區的 redo 日誌寫入磁盤的日誌文件,而是等待主線程每秒刷新。
  • 1:在事務提交時將緩衝區的 redo 日誌同步寫入到磁盤,保證必定會寫入成功。
  • 2:在事務提交時將緩衝區的 redo 日誌異步寫入到磁盤,即不能徹底保證 commit 時確定會寫入 redo 日誌文件,只是有這個動做。

咱們使用默認值 1 就好,這樣能夠保證 MySQL 異常重啓以後數據不丟失。

總結一下 redo 日誌是 InnoDB 引擎特有的,有了 redo 日誌 以後,InnoDB 就能夠保證即便數據庫發生異常重啓,以前提交的記錄都不會丟失。

這篇文章從爲何要引入 redo 日誌、redo 日誌的結構和 redo 日誌的寫入方式三個方面簡單聊了一下 MySQL 持久化保障機制 redo 日誌,這東西可能工做沒啥用,面試時候可能用的上,但願這篇文章對你的學習或者工做有所幫助,感謝您的閱讀,若是您以爲文章有收穫,歡迎點個贊和轉發,謝謝。

最後

目前互聯網上不少大佬都有 MySQL 相關文章,若有雷同,請多多包涵了。原創不易,碼字不易,還但願你們多多支持。若文中有所錯誤之處,還望提出,謝謝。

歡迎掃碼關注微信公衆號:「平頭哥的技術博文」,和平頭哥一塊兒學習,一塊兒進步。

平頭哥的技術博文
相關文章
相關標籤/搜索