阿里天貓二面:MySQL Double Write Buffer是什么?架構是怎樣的?為什么能保證崩潰恢復...
InnoDB 是 MySQL 中一種常用的事務性存儲引擎,它具有很多優秀的特性。其中,Doublewrite Buffer 是 InnoDB 的一個重要特性之一。
本文將介紹Doublewrite Buffer的原理和應用。
- 為什么需要 Doublewrite Buffer?
- Doublewrite Buffer 的架構設計和實現原理是什么?
- Redo Log 與 不是可以實現崩潰恢復了碼?為何還需要 Doublewrite Buffer?
為什么需要 Doublewrite Buffer
InnoDB 頁大小為 16KB,而操作系統(如 Linux)頁大小為 4KB,單次寫入需拆分 4 個 OS 頁。
可以使用如下命令查看 MySQL 的 Page 大?。?/span>
SHOW VARIABLES LIKE 'innodb_page_size';
MySQL 程序是跑在 Linux 操作系統上的,需要跟操作系統交互,所以 MySQL 中一頁數據刷到磁盤,要寫 4 個文件系統里的頁。
圖片
需要注意的是,這個操作并非原子操作,比如我操作系統寫到第二個頁的時候,Linux 機器斷電了,這時候就會出現問題了。
造成”頁數據損壞“。并且這種”頁數據損壞“靠 redo 日志是無法修復的。
Redo log 中記錄的是對頁的物理操作,而不是頁面的全量記錄,而如果發生 partial page write(部分頁寫入)問題時,出現問題的是未修改過的數據,此時重做日志(Redo Log)無能為力。
Doublewrite Buffer 的出現就是為了解決上面的這種情況,雖然名字帶了 Buffer,但實際上 Doublewrite Buffer 是內存+磁盤的結構。
Doublewrite Buffer 是一種特殊文件 flush 技術,帶給 InnoDB 存儲引擎的是數據頁的可靠性。
它的作用是,在把頁寫到數據文件之前,InnoDB 先把它們寫到一個叫 doublewrite buffer(雙寫緩沖區)的共享表空間內,在寫 doublewrite buffer 完成后,InnoDB 才會把頁寫到數據文件的適當的位置。
如果在寫頁的過程中發生意外崩潰,InnoDB 在稍后的恢復過程中在 doublewrite buffer 中找到完好的 page 副本用于恢復。
架構設計
Doublewrite Buffer 采用 內存+磁盤雙層結構,關鍵組件如下:
圖片
內存結構
- 容量固定為 128 個頁(2MB),每個頁 16KB。
- 數據頁刷盤前,通過
memcpy
拷貝至內存 Doublewrite Buffer。
磁盤結構
- 位于系統表空間(
ibdata
),分為 2 個區(extent1/extent2),共 2MB。 - 數據以 順序寫 方式寫入,避免隨機 I/O 開銷。
工作流程如下圖所示:
圖片
如上圖所示,當有數據修改且頁數據要刷盤時:
- 第一步:記錄 Redo log。
- 第二步:臟頁從 Buffer Pool 拷貝至內存中的 Doublewrite Buffer。
- 第三步:Doublewrite Buffer 的內存里的數據頁,會 fsync 刷到 Doublewrite Buffer 的磁盤上,分兩次寫入磁盤共享表空間中(連續存儲,順序寫,性能很高),每次寫 1MB;
- 第四步:Doublewrite Buffer 的內存里的數據頁,再刷到數據磁盤存儲 .ibd 文件上(離散寫);
時序圖如下:
圖片
崩潰恢復
如果第三步前,發生了崩潰,可以通過第一步記錄的 Redo log 來恢復。
如果第三步完成后發生了崩潰, InnoDB 存儲引擎可以從共享表空間中的 Double write 中找到該頁的一個副本,將其復制到獨立表空間文件,再應用 Redo log 恢復。
在正常的情況下,MySQL 寫數據頁時,會寫兩遍到磁盤上,第一遍是寫到 doublewrite buffer,第二遍是寫到真正的數據文件中,這就是“Doublewrite”的由來。
Doublewrite Buffer 通過 兩次寫 機制,在內存和磁盤間構建冗余副本,成為 InnoDB 保障數據完整性的基石。
其架構設計平衡了性能與可靠性,尤其在高并發或異常宕機場景下表現突出。