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