【Mysql】三大日誌 redo log、bin log、undo log

cooper發表於2021-11-24

@

redo log(物理日誌\重做日誌)

redo log是InnoDB儲存引擎層的日誌,又稱重做日誌檔案,是物理日誌。redo log記錄資料修改後新資料的備份、冗雜的undo log、未提交的事務和回滾的事務,資料快取到記憶體中,只是在事務提交前將redo log持久化到磁碟

redo log 可以保證即使資料庫發生異常重啟,之前提交的記錄都不會丟失,保證了事務的永續性

當有一條記錄需要更新的時候,InnoDB引擎就會先把記錄寫到redo log中,並更新記憶體。之後,InnoDB引擎會在適當的時候,將這個操作更新到磁碟中,這個更新是在系統比較空閒的時候做,他的關鍵點是先寫日誌,再寫磁碟。

redo log日誌大小是固定的,若空間滿了以後會回到頭部停止更新,先載入一些資料到磁碟讓出檔案空間,之後繼續寫入


物理日誌:因為mysql資料最終是儲存在資料頁中的,物理日誌記錄的就是資料頁變更

為了保證Redo Log能夠有比較好的IO效能,InnoDB 的 Redo Log的設計有以下幾個特點:

  • 儘量保持Redo Log儲存在一段連續的空間上。因此在系統第一次啟動時就會將日誌檔案的空間完全分配。以順序追加的方式記錄Redo Log,通過順序IO來改善效能。

  • redo log包括兩部分:一是記憶體中的日誌緩衝(redo log buffer),該部分日誌是易失性的;二是磁碟上的重做日誌檔案(redo log file),該部分日誌是持久的。日誌並不是直接寫入檔案的,而是先寫入日誌緩衝,當需要將日誌重新整理到磁碟時(如事務提交),將許多日誌一起寫入磁碟.

  • 併發的事務共享Redo Log的儲存空間,它們的Redo Log按語句的執行順序,依次交替的記錄在一起,以減少日誌佔用的空間。所以,當一個事務將Redo Log寫入磁碟時,也會將其他未提交**的事務的日誌寫入磁碟。

  • Redo Log上只進行順序追加的操作,當一個事務需要回滾時,它的Redo Log記錄也不會從Redo Log中刪除掉。


注意

一般在事務提交之前會將redo log持久化到磁碟中,以此來保證永續性



binlog(邏輯日誌/歸檔日誌)

binlog是屬於MySQL Server層面的,又稱為歸檔日誌,屬於邏輯日誌,是以二進位制的形式記錄的是這個語句的原始邏輯,依靠binlog是沒有CrashSafe能力的

邏輯日誌:可以簡單理解為記錄的就是sql語句

binlog主要使用場景:主從複製資料恢復

主從複製:在Master端開啟binlog,然後將binlog傳送到各個Slave端,Slave端重放binlog從而達到主從資料一致。

資料庫恢復方法

系統會定期整庫備份,binlog會記錄所有的邏輯操作,當需要恢復到指定的某一時刻時:

  • 首先,找到最近的一次全量備份
  • 然後,從備份時間開始,將binlog依次取出來,一直重放到指定的時刻

為什麼 redo log 具有 crash-safe 的能力,而 binlog 沒有?

CrashSafe指MySQL伺服器當機重啟後,能夠保證:
- 所有已經提交的事務的資料仍然存在。
- 所有沒有提交的事務的資料自動回滾。

當資料庫 crash(崩潰) 後,想要恢復未刷盤但已經寫入 redo log binlog 的資料到記憶體時,binlog 是無法恢復的。雖然 binlog 擁有全量的日誌,但沒有一個標誌讓 innoDB 判斷哪些資料已經刷盤,哪些資料還沒有。

redo log 不一樣,只要刷入磁碟的資料,都會從 redo log 中抹掉,資料庫重啟後,直接把 redo log 中的資料都恢復至記憶體就可以了。這就是為什麼 redo log 具有crash-safe的能力,而binlog 不具備。


redo log 和 binlog的區別:

  1. redo log是InnoDB特有的日誌,binlog 所有引擎都可以使用
  2. redo log是物理日誌,記錄的是該資料頁更新的內容;binlog是邏輯日誌,記錄的是這個更新語句的原始邏輯
  3. redo log是迴圈寫的,空間固定會用完。binlog是可以追加寫的,當binlog寫到一定大小會切換到下一個,並不會覆蓋以前的日誌
  4. binlog可以作為恢復資料使用,主從複製搭建,redo log作為異常當機或者介質故障後的資料恢復使用。

update語句執行流程

首先進行sql查詢語句的執行流程,如需 update ID = 2 ,先找到這一行,執行以下流程:

image-20211121192944090

為什麼update語句 要有兩階段提交?

這是為了讓兩份日誌之間的邏輯一致。

當執行update語句時,資料修改完更新到記憶體,先寫redo log 並設定redo log為準備階段,再寫binlog,寫完binlog設定為redo log為結束階段。兩個中間有一個寫入差錯,那麼該操作都是失敗,即redo log發現只有準備階段沒有結束,那麼會將該條事務進行回滾。


假如不採用兩階段提交機制的話那麼會有什麼影響呢?
(1)先寫redo log:當寫完redo log裝置斷電,binlog沒有記錄,那麼資料庫剛剛啟動之後通過redo log可以恢復到斷電前的狀態,但是由於binlog沒有寫入,當從某個節點進行恢復時(或者建立一個備份庫),那麼binlog沒用這條記錄,恢復出來的資料庫是有錯誤的。
(2)先寫binlog:當寫完binlog裝置斷電,redo log沒有記錄,還沒有寫入磁碟,那麼資料庫重新啟動之後通過redo log恢復並沒有這條資料,而當從某個時間點進行恢復(或者建立一個備份庫)時,binlog有相關資料,所以會導致資料不統一。



Uodolog(回滾日誌/重做日誌)

Undo Log 是為了實現事務的原子性,事務中執行失敗,進行回滾,在MySQL資料庫 InnoDB 儲存引擎中,還用Undo Log來實現多版本併發控制(簡稱:MVCC)。由引擎層的InnoDB引擎實現,是邏輯日誌,記錄資料修改被修改前的值。


原理:

Undo Log的原理很簡單,為了滿足事務的原子性,在操作任何資料之前,首先將資料備份到Undo Log。然後進行資料的修改。如果出現了錯誤或者使用者執行了ROLLBACK語句,系統可以利用Undo Log中的備份將資料恢復到事務開始之前的狀態。


回滾時機?

  • 使用者呼叫 rollback 主動回滾
  • 事務出錯
  • 輔助 redo log 實現事務永續性

當事務提交的時候,innodb不會立即刪除undo log,因為後續還可能會用到undo log,如隔離級別為repeatable read時,事務讀取的都是開啟事務時的最新提交行版本,只要該事務不結束,該行版本就不能刪除,即undo log不能刪除。

但是在事務提交的時候,會將該事務對應的undo log放入到刪除列表中,未來通過purge來刪除。並且提交事務時,還會判斷undo log分配的頁是否可以重用,如果可以重用,則會分配給後面來的事務,避免為每個獨立的事務分配獨立的undo log頁而浪費儲存空間和效能。

undo log+redo log保證永續性

除了可以保證事務的原子性,Undo Log也可以用來輔助完成事務的持久化,如資料庫異常之後的恢復機制。

因為未提交的事務和回滾了的事務也會記錄在Redo Log,因此在進行恢復時,這些事務要進行特殊的的處理。有2種不同的恢復策略:

A. 進行恢復時,只重做已經提交了的事務。
B. 進行恢復時,重做所有事務包括未提交的事務和回滾了的事務。然後通過Undo Log回滾那些未提交的事務。

MySQL資料庫InnoDB儲存引擎使用了B策略,InnoDB儲存引擎中的恢復機制有幾個特點:

  • Undo Log回滾那些未提交的事務,被回滾了的事務在恢復時先redoundo,也不會破壞資料的一致性

  • ​ 必須要在寫Redo Log之前將對應的Undo Log寫入磁碟。為了降低複雜度,InnoDB將Undo Log看作資料,因此記錄Undo Log的操作也會記錄到redo log中。這樣undo log就可以象資料一樣快取起來,而不用在redo log之前寫入磁碟了。


參考:

極客時間 mysql45講

https://www.qiancheng.me/post/coding/mysql-001

說說MySQL中的Redo log Undo log都在幹啥 - 蘇家小蘿蔔 - 部落格園 (cnblogs.com)

詳細分析MySQL事務日誌(redo log和undo log) - 駿馬金龍 - 部落格園 (cnblogs.com)

MySQL事務日誌undo log和redo log分析

相關文章