double write buffer,你居然沒聽過?

MySQL採用buffer機制,避免每次讀寫進行磁盤IO,提升效率:

  • 《緩衝池(buffer pool)》
  • 《寫緩衝(change buffer)》
  • 《日誌緩衝(log buffer)》

MySQL的buffer一頁的大小是16K,文件系統一頁的大小是4K,也就是說,MySQL將buffer中一頁數據刷入磁盤,要寫4個文件系統裡的頁。

double write buffer,你居然沒聽過?

如上圖所示,MySQL裡page=1的頁,物理上對應磁盤上的1+2+3+4四個格。

那麼,問題來了,這個操作並非原子,如果執行到一半斷電,會不會出現問題呢?
會,這就是所謂的“頁數據損壞”。

double write buffer,你居然沒聽過?

如上圖所示,MySQL內page=1的頁準備刷入磁盤,才刷了3個文件系統裡的頁,掉電了,則會出現:重啟後,page=1的頁,物理上對應磁盤上的1+2+3+4四個格,數據完整性被破壞。

畫外音:redo無法修復這類“頁數據損壞”的異常,修復的前提是“頁數據正確”並且redo日誌正常。

如何解決這類“頁數據損壞”的問題呢?

很容易想到的方法是,能有一個“副本”,對原來的頁進行還原,這個存儲“副本”的地方,就是Double Write Buffer。

Double Write Buffer,但它與傳統的buffer又不同,它分為內存磁盤的兩層架構。

畫外音:傳統的buffer,大部分是內存存儲;而DWB裡的數據,是需要落地的。

double write buffer,你居然沒聽過?

如上圖所示,當有頁數據要刷盤時:

第一步:頁數據先memcopy到DWB的內存裡;

第二步:DWB的內存裡,會先刷到DWB的磁盤上;

第三步:DWB的內存裡,再刷到數據磁盤存儲上;

畫外音:DWB由128個頁構成,容量只有2M。

步驟2和步驟3要寫2次磁盤,這就是“Double Write”的由來。

DWB為什麼能解決“頁數據損壞”問題呢?

假設步驟2掉電,磁盤裡依然是1+2+3+4的完整數據。

畫外音:只要有頁數據完整,就能通過redo還原數據。

假如步驟3掉電,DWB裡存儲著完整的數據。

所以,一定不會出現“頁數據損壞”問題。

畫外音:寫了2次,總有一個地方的數據是OK的。

自己實驗了幾十次,仍沒能復現“頁數據損壞”,在網上找了一個“頁數據損壞”時,MySQL重啟過程利用DWB修復頁數據的圖。

double write buffer,你居然沒聽過?

可以看到,啟動過程中:

(1)InnoDB檢測到上一次為異常關閉;

(2)嘗試恢復ibd數據,失敗;

(3)從DWB中恢復寫了一半的頁;

能夠通過DWB保證頁數據的完整性,但畢竟DWB要寫兩次磁盤,會不會導致數據庫性能急劇降低呢?


分析DWB執行的三個步驟:

(1)第一步,頁數據memcopy到DWB的內存,速度很快;

(2)第二步,DWB的內存fsync刷到DWB的磁盤,屬於順序追加寫,速度也很快;

(3)第三步,刷磁盤,隨機寫,本來就需要進行,不屬於額外操作;

另外,128頁(每頁16K)2M的DWB,會分兩次刷入磁盤,每次最多64頁,即1M的數據,執行也是非常之快的。

綜上,性能會有所影響,但影響並不大。

畫外音:

(1)write­-ahead-log之所以性能高,就是因為順序追加寫;

(2)有第三方測評,評估約10%性能損失;

更具體的,InnoDB裡有兩個變量可以查看double write buffer相關的情況:

Innodb_dblwr_pages_written

記錄寫入DWB中頁的數量。

Innodb_dblwr_writes

記錄DWB寫操作的次數。

可以通過:

show global status like "%dblwr%"

來進行查詢。

double write buffer,你居然沒聽過?

結尾

MySQL有很強的數據安全性機制

(1)在異常崩潰時,如果不出現“頁數據損壞”,能夠通過redo恢復數據;

(2)在出現“頁數據損壞”時,能夠通過double write buffer恢復頁數據;

double write buffer

(1)不是一個內存buffer,是一個內存/磁盤兩層的結構,是InnoDB裡On-Disk架構裡很重要的一部分;

(2)是一個通過寫兩次,保證頁完整性的機制;

知其然,知其所以然。

思路比結論重要,希望大家有收穫。


分享到:


相關文章: