MySQL 高頻八股——事務過程中 Undo log、Redo log、Binlog 的寫入順序(涉及兩階段提交)
大家好,我是鋼板獸!
在上一篇文章中,我分別介紹了 Undo Log、Redo Log 和 Binlog 在事務執行過程中的作用與寫入機制。然而,實際應用中,這三種日誌的寫入是有先後順序的。因此,本篇文章將深入探討它們的寫入順序,以便更好地理解三者與事務的聯繫。
1. 涉及的關鍵緩存
在事務執行過程中,涉及多個重要的緩存機制,理解這些緩存有助於更清晰地掌握日誌的寫入順序:
-
Buffer Pool(緩衝池)存儲 InnoDB 數據頁的內存緩衝區,事務修改數據頁首先在此處完成,修改後的數據頁被稱爲髒頁(Dirty Page)。
-
Undo Log Buffer(Undo 日誌緩存區) 記錄事務修改前的數據版本,存儲於內存,在特定時機刷新到磁盤的 Undo 表空間。
-
Redo Log Buffer(Redo 日誌緩存區) 存儲事務修改後的數據變化記錄(物理日誌),位於內存中,在事務提交時強制刷新到磁盤的 Redo 日誌文件。
-
Binlog Cache(Binlog 緩存區) MySQL Server 層的內存緩存,存儲事務中修改的數據變化記錄(邏輯變化),在事務提交時統一刷入磁盤的 Binlog 文件。
2. 事務執行階段各日誌的寫入流程
事務可以分爲兩個階段:事務執行階段和事務提交階段,假設我們有一個更新事務的 SQL 語句:
UPDATE account SET balance = balance - 100 WHERE id = 1;
我們先來看看事務執行階段各日誌的寫入流程:
(1)數據頁加載到 buffer pool:從磁盤中加載數據頁到 buffer pool;
(2)寫入 Undo Log Buffer:先把待修改數據的原始版本(例如 balance=1000)記錄到內存中的 Undo Log Buffer 中。
- 這個 Undo Log Buffer 會在合適時機(後臺線程)異步刷新到磁盤(Undo 表空間)。
(3)數據頁(髒頁)的修改:事務修改內存中的數據頁(buffer pool),修改後的數據頁變爲髒頁(Dirty Page),等待後臺線程(如 checkpoint)異步刷新到磁盤上的表空間文件(.ibd 文件)。
(4)寫入 Redo Log Buffer:數據庫會把修改後的數據記錄(例如:balance=900)記錄到內存中的 Redo Log Buffer 中。
-
Redo Log Buffer 會在以下幾種情況下被刷新到磁盤(Redo Log File):
-
事務提交時;
-
Redo Log Buffer 達到指定閾值;
-
後臺線程定期刷新。
(5)寫入 Binlog Cache:把 SQL 語句邏輯記錄到內存中的 Binlog Cache。
到這裏爲止(事務未提交階段),此時的日誌情況爲:
-
Undo Log Buffer 已寫入舊版本數據;
-
Redo Log Buffer 中包含數據修改後的版本記錄;
-
Buffer Pool 中的數據頁被真正修改,處於內存髒頁狀態。
-
Binlog Cache 中包含此次修改的 SQL 語句邏輯。
3. 事務提交階段
事務提交採用兩階段提交(2PC)機制:Prepare 階段(半提交狀態)和 Commit 階段(已提交狀態),
(1)Prepare 狀態:InnoDB 存儲引擎將 Redo Log Buffer 中的日誌記錄強制刷入磁盤上的 Redo Log File(調用 write 和 fsync),Undo Log 也是同樣的過程。
- 此時 Redo Log 已持久化,但 Binlog 尚未刷入磁盤。
(2)MySQL 層將 Binlog Cache 中的日誌記錄刷新到磁盤中的 Binlog 文件(調用 write 和 fsync)。
(3)Commit 狀態:執行器調用 InnoDB 存儲引擎的提交事務接口,將剛剛寫入的 Redo Log 改成 Commit 狀態
4. 爲什麼要兩階段提交?
這裏的兩階段提交主要是針對 Redo Log 和 Binlog 來說的,爲什麼不能是先寫 Redo Log 後寫 binlog,或者先寫 binlog 後寫 Redo Log 就完事兒了呢,還要從中多出一個 “Prepare 狀態”?
(1)假設是先寫 Redo Log,後寫 binlog。向表中插入一條數據 R,當 redolog 寫入完成,但是 binlog 還沒寫時,就出現了宕機. 那麼主機崩潰恢復時,redolog 中是有記錄 R 的,但是從機根據 binlog 進行主從同步時,從機是沒有數據 R,就會出現主從數據不一致的問題。
(2)假設先寫 binlog 再寫 redolog 。向表中插入一條記錄 R,先寫 binlog 再寫 redolog,當 binlog 寫入完成,但是 redolog 還沒寫時,就出現了宕機,那麼從機根據 binlog 進行主從同步時,從機是有數據 R 的。但是主機崩潰恢復時,redolog 中是沒有記錄 R 的,就會出現主從數據不一致的問題。
但是現在 “兩階段提交”,我們再來看幾種情況:
(1)一階段提交之後崩潰了,即寫入 redo log,處於 prepare 狀態
的時候崩潰了,此時,由於 binlog 還沒寫,redo log 處於 prepare 狀態還沒提交,所以崩潰恢復的時候,這個事務會根據 undolog 來回滾,此時 binlog 還沒寫,所以也不會傳到備庫。
(2)寫完 binlog 之後崩潰了,此時:redolog 中的日誌處於 prepare 狀態,還沒有提交,那麼恢復的時候,首先檢查 binlog 中的事務是否存在並且完整,如果存在且完整,則直接提交事務,如果不存在或者不完整,則回滾事務。
(3)假設 redolog 處於 Commit 狀態的時候崩潰了,那麼重啓後的處理方案同情況二。
最後,我們來畫圖總結一下三種日誌在事務過程中的寫入順序:
5. 三種日誌寫入的參數
這裏總結一下三種日誌的寫入過程涉及到的參數變量,可以瞭解一下。
(1)Redo Log 的參數
(2)Binlog 的參數
(3)Undo Log 的參數
關鍵參數:
通過本篇文章的講解,相信大家對 Undo Log、Redo Log 和 Binlog 的寫入順序及其重要性有了更深入的理解。如果這篇文章對你有所幫助,歡迎點贊、轉發、留言!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/8-eUzJCI5Q4tcFzkeiJZtg