天天看點

MySQL InnoDB 的 Double Write Buffer

參考原文: http://blog.itpub.net/22664653/viewspace-1140915/ id="tmp_downloadhelper_iframe" style="display: none;">

partial page write 問題

InnoDB 的 Page Size 一般是 16KB,其資料校驗也是針對這 16KB 來計算的,将資料寫入到磁盤是以 Page 為機關進行操作的。而計算機硬體和作業系統,在極端情況下(比如斷電)往往并不能保證這一操作的原子性,16K 的資料,寫入 4K 時(os 層面的原子 block 一般為 4K,可以調),發生了系統斷電 / os crash ,隻有一部分寫是成功的,這種情況下就是 partial page write 問題。

很多 DBA 會想到系統恢複後,MySQL 可以根據 redolog 進行恢複,而 mysql 在恢複的過程中會檢查 page 的 checksum,checksum 就是 page 的最後事務号,發生 partial page write 問題時,page 已經損壞,找不到該 page 中的事務号,就無法恢複。

為了解決 partial page write 問題 ,當 mysql 将髒資料 flush 到 data file 的時候, 先使用 memcopy 将髒資料複制到記憶體中的 doublewrite buffer ,之後通過 doublewrite buffer 再分 2 次,每次寫入 1MB 到共享表空間,然後馬上調用 fsync 函數,同步到磁盤上,避免緩沖帶來的問題,在這個過程中,doublewrite 是順序寫,開銷并不大,在完成 doublewrite 寫入後,再将 doublewrite buffer 寫入各表空間檔案,這時是離散寫入。(個人觀點:doublewrite 是在刷髒的時候先寫的,fsync 完 doublewrite 後再 fsync data file。 如果操作都沒問題,doublewrite 可以被後面的資料覆寫,是以不存在 doublewrite 空間不夠的情況。)

如果發生了極端情況(斷電),InnoDB 再次啟動後,發現了一個 Page 資料已經損壞,那麼此時就可以從 doublewrite 中進行資料恢複了。(盜圖,圖可能有問題,個人了解第 5 步應該為: flush redo logfile 到磁盤; 第 6 步應該為: copy dirty page 到 DWB, 再 write 到 tablespace,再 flush; 第 7 步應該為: flush data page 到磁盤; 第 8 步應該為: 從 tablespace 中恢複壞塊)

MySQL InnoDB 的 Double Write Buffer

doublewrite 的缺點是什麼

位于共享表空間上的 doublewrite 實際上也是一個檔案,寫 DW 會導緻系統有更多的 fsync 操作,即更多的 IO 操作,是以它會降低 mysql 的整體性能。但是并不會降低到原來的 50%。這主要是因為:

  • doublewrite 是一個連續的存儲空間,是以硬碟在寫資料的時候是順序寫,而不是随機寫,這樣性能更高。
  • 将資料從 double write buffer 寫到真正的 segment 中的時候,系統會合并連接配接空間重新整理的方式,每次可以重新整理多個 page(個人了解:這個地方的意思是,合并多個 page 後一次性刷入 doublewrite)。

doublewrite 在恢複的時候是如何工作的

  • If there’s a partial page write to the doublewrite buffer itself, the original page will still be on disk in its real location.

    如果是寫 doublewrite 本身失敗,那麼這些資料不會被寫到磁盤,InnoDB 此時會從磁盤載入原始的資料,然後通過 InnoDB 的事務日志來計算出正确的資料,重新寫入到 double write buffer.

  • When InnoDB recovers, it will use the original page instead of the corrupted copy in the doublewrite buffer. However, if the doublewrite buffer succeeds and the write to the page’s real location fails, InnoDB will use the copy in the doublewrite buffer during recovery.

    如果 doublewrite 寫成功,但是寫磁盤失敗,InnoDB就不用通過事務日志來計算了,而是直接用 DW 的資料再寫一遍.

  • InnoDB knows when a page is corrupt because each page has a checksum at the end; the checksum is the last thing to be written, so if the page’s contents don’t match the checksum, the page is corrupt. Upon recovery, therefore, InnoDB just reads each page in the doublewrite buffer and verifies the checksums. If a page’s checksum is incorrect, it reads the page from its original location.

    在恢複的時候,InnoDB 直接比較頁面的 checksum,如果不對的話,就從硬碟載入原始資料,再由事務日志開始推演出正确的資料,是以 InnoDB 的恢複通常需要較長的時間.(補充: 能直接從事務日志和原資料推導出來,那 DW 還有什麼用,是在 page 寫壞連 page no 都找不到這才是問題吧?)

我們是否一定需要 doublewrite

In some cases, the doublewrite buffer really isn’t necessary—for example, you might want to disable it on slaves. Also, some filesystems (such as ZFS) do the same thing themselves, so it is redundant for InnoDB to do it. You can disable the doublewrite buffer by setting InnoDB_doublewrite to 0.

如何使用 double write

InnoDB_doublewrite = 1表示啟動 double write

show status like ‘InnoDB_dblwr%’ 可以查詢 double write 的使用情況。

InnoDB_dblwr_pages_written:從bp flush 到 DWB的個數

InnoDB_dblwr_writes :寫檔案的次數

每次寫操作合并 page 的個數 = InnoDB_dblwr_pages_written / InnoDB_dblwr_writes