1、doublewrite buffer(mysql官方的介紹)
InnoDB uses a novel file flush technique called doublewrite. Before writing pages to the data files, InnoDB first writes them to a contiguous area called the doublewrite buffer. Only after the write and the flush to the doublewrite buffer have completed, does InnoDB write the pages to their proper positions in the data file. If there is an operating system, storage subsystem, or mysqld process crash in the middle of a page write, InnoDB can later find a good copy of the page from the doublewrite buffer during crash recovery.
Although data is always written twice, the doublewrite buffer does not require twice as much I/O overhead or twice as many I/O operations. Data is written to the buffer itself as a large sequential chunk, with a single fsync()
call to the operating system.
To turn off the doublewrite buffer, specify the option innodb_doublewrite=0
.
2、partial page write
InnoDB 的Page Size一般是16KB,其數據校驗也是針對這16KB來計算的,將數據寫入到磁盤是以Page為單位進行操作的。而計算機硬件和操作系統,在極端情況下 (比如斷電)往往並不能保證這一操作的原子性,16K的數據,寫入4K 時,發生了系統斷電/os crash ,只有一部分寫是成功的,這種情況下就是 partial page write 問題。
很多DBA 會想到系統恢復後,MySQL 可以根據redo log 進行恢復,而mysql在恢復的過程中是檢查page的checksum,checksum就是pgae的最後事務號,發生partial page write 問題時,page已經損壞,找不到該page中的事務號,就無法恢復
所以說,當page 損壞之後,其實應用redo是沒有意義的,這時候無法使用redo來恢復,因為原始頁已經損壞了,會發生數據丟失。
在InnoDB將BP中的Dirty Page刷(flush)到磁盤上時,首先會將(memcpy函數)Page刷到InnoDB tablespace的一個區域中,我們稱該區域為Double write Buffer(大小為2MB,每次寫入1MB)。在向Double write Buffer寫入成功後,第二步、再將數據拷貝到數據文件對應的位置。
當第二步過程中發生故障,也就是發生partial page write的問題。恢復的時候先檢查頁內的checksum是否相同,不一致,則直接從doublewrite中恢復。
1)如果寫dw buffer失敗。那麼這些數據不會寫到磁盤,innodb會載入磁盤原始數據和redo日志比較,並重新刷到dw buffer。
2)如果寫dw buffer成功,但是刷新到磁盤失敗,那麼innodb就不會通過事務日志來恢復了,而是直接刷新dw buffer中的數據。
4、對性能的影響
系統需要將數據寫兩份,一般認為,Double Write是會降低系統性能的。peter猜測可能會有5-10%的性能損失,但是因為實現了數據的一致,是值得的。Mark Callaghan認為這應該是存儲層面應該解決的問題,放在數據庫層面無疑是犧牲了很多性能的。
事實上,Double Write對性能影響並沒有你想象(寫兩遍性能應該降低了50%吧?)的那麼大。在BP中一次性往往會有很多的Dirty Page同時被flush,Double Write則把這些寫操作,由隨機寫轉化為了順序寫。而在Double Write的第二個階段,因為Double Write Buffer中積累了很多Dirty Page,所以向真正的數據文件中寫數據的時候,可能有很多寫操作可以合並,這樣有可能會降低Fsync的調用次數。
基於上面的原因,Double Write並沒有想象的那麼糟。另外,Dimitri在測試後,發現打開和關閉Double Write對效率的影響並不大。
5、doublewrite參數
mysql> show variables like "%double%"; +--------------------+-------+ | Variable_name | Value | +--------------------+-------+ | innodb_doublewrite | ON | +--------------------+-------+ 1 row in set (0.00 sec) mysql> SHOW STATUS LIKE "%innodb_dblwr%"; +----------------------------+-------+ | Variable_name | Value | +----------------------------+-------+ | Innodb_dblwr_pages_written | 447 | | Innodb_dblwr_writes | 38 | +----------------------------+-------+ 2 rows in set (0.00 sec)
從上面可以看出, Flush了447次到doublewrite buffer中,寫文件共38次,則每次write合並了447/38次flush
參考文章
http://www.percona.com/blog/2006/08/04/innodb-double-write/
http://www.percona.com/doc/percona-server/5.5/performance/innodb_doublewrite_path.html?id=percona-server:features:percona_innodb_doublewrite_path
http://dev.mysql.com/doc/refman/5.0/en/innodb-disk-io.html
http://www.mysqlperformanceblog.com/2006/08/04/innodb-double-write/
http://www.facebook.com/note.php?note_id=107329775932
http://dimitrik.free.fr/blog/archives/2009/08/entry_86.html