InnoDB儲存引擎——兩次寫

readyao發表於2017-03-14

Insert Buffer給InnoDB儲存引擎帶來的是效能上的提升,doublewrite(兩次寫)給InnoDB儲存引擎帶來的是資料頁的可靠性。

當資料庫發生當機時,可能InnoDB儲存引擎正在寫入某個頁表中,而這個頁只寫了一部分,比如16K的頁,只寫了前4K,之後就發生了當機,這種情況被稱為部分寫失效。
在InnoDB儲存引擎未使用doublewrite技術前,曾經出現過因為部分寫失效而導致資料丟失的情況。

這裡寫圖片描述

doublewrite由兩部分組成,一部分是記憶體中的doublewrite buffer,大小為2MB,另一部分是物理磁碟上共享表空間中連續的128個頁,即2個區(extent),大小也為2MB。
第一次寫:在對緩衝池的髒頁進行重新整理時,並不直接寫磁碟,而是會通過memcpy函式將髒頁先複製到記憶體中的doublewrite buffer,之後通過doublewrite buffer再分兩次,每次1MB順序地寫入共享表空間的物理磁碟上,然後馬上呼叫fsync函式,同步磁碟,避免緩衝寫帶來的問題。這個過程中是順序寫的,所以開銷並不大。
第二次寫:在完成doublewrite頁的寫入後,再將doublewrite buffer中的頁寫入各個表空間檔案中,此時的寫入是離散的。
可以通過下面的命令觀察到doublewrite執行的情況:

mysql> show global status like 'innodb_dblwr%'\G
*************************** 1. row ***************************
Variable_name: Innodb_dblwr_pages_written
        Value: 0
*************************** 2. row ***************************
Variable_name: Innodb_dblwr_writes
        Value: 0
2 rows in set (0.03 sec)

從上面可以看出doublewirte一共寫了Innodb_dblwr_pages_written個頁,但實際的寫入次數為Innodb_dblwr_writes。

如果作業系統在第二次寫的時候,也就是從doublewrite buffer中將頁寫入到磁碟的過程中發生了崩潰,在恢復過程中,InnoDB儲存引擎可以從共享表空間中的doublewrite中找到該頁的一個副本,將其複製到表空間中,再應用重做日誌。

Innodb_buffer_pool_pages_flushed變數表示當前緩衝池中重新整理到磁碟頁的數量。因為在預設情況下,緩衝中的所有頁首先都需要放入到doublewrite中,因此該變數應該和Innodb_dblwr_pages_written一致。

引數skip_innodb_doulewrite可以禁止使用doublewrite功能,不過這時可能會引起前面說的寫失效問題。

有些檔案系統本身就提供了部分寫失效的防範機制,比如ZFS檔案系統。在這種情況下,使用者就不要啟動doublewrite了。

相關文章