天天看點

double write buffer,你居然沒聽過?

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

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)是一個通過寫兩次,保證頁完整性的機制; 知其然,知其是以然。思路比結論重要,希望大家有收獲。

本文轉自“架構師之路”公衆号,58沈劍提供。