mysql的頁斷裂(partial write)問題與(double write)技術(shù)

1. 頁斷裂

1.1 什么叫做頁斷裂(partial write)

頁斷裂是數(shù)據(jù)庫宕機(jī)時,數(shù)據(jù)庫頁面只有部分寫入磁盤,導(dǎo)致頁面出現(xiàn)不一致的情況。

1.2 為什么會發(fā)生頁斷裂

InnoDB中有記錄(Row)被更新時,先將其在Buffer Pool中的page更新,并將這次更新記錄到Redo Log file中,這時候Buffer Pool中的該page就是被標(biāo)記為Dirty(臟頁)。在適當(dāng)?shù)臅r候(Buffer Pool不夠、Redo不夠,系統(tǒng)閑置等),這些Dirty Page會被Checkpoint刷新到磁盤進(jìn)行持久化操作。

mysql的一個update需要經(jīng)歷什么最終持久化到磁盤?

我們知道,InnoDB的Page Size是16KB,其數(shù)據(jù)校驗(yàn)也是針對這16KB來計(jì)算的,將數(shù)據(jù)寫入到磁盤是以Page為單位進(jìn)行操作的。我們知道文件系統(tǒng)是以4k為單位寫入,機(jī)械磁盤是以扇區(qū)(512字節(jié))為單位寫入(SSD本質(zhì)上雖然沒有扇區(qū)概念,但為了兼容機(jī)械盤,也搞出了這么一個512字節(jié)扇區(qū)這么一個寫方式),不能保證MySQL數(shù)據(jù)頁面16KB的一次性原子寫。試想,在某個Dirty Page flush的過程中,發(fā)生了系統(tǒng)斷電(或者OS崩潰),16K的數(shù)據(jù)只有8K被寫到磁盤上,只有一部分寫是成功的,這種現(xiàn)象被稱為(partial page writes、torn pages、fractured writes)。

查看innoDB的Page Size大小

mysql> show variables like 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
1 row in set (0.00 sec)

查看OS block Size大小

$ getconf PAGESIZE

4096

1.3 InnoDB使用redo log可以恢復(fù)頁斷裂嗎

一旦partial page writes發(fā)生,那么在InnoDB恢復(fù)時就很尷尬:redo log的頁大小一般設(shè)計(jì)為512個字節(jié),因此redo log page本身不會發(fā)生break page。用redo log來解決partial write 理論上是可行的,不過innodb的redo log是物理邏輯日志,并不是純物理日志,因此發(fā)生partial write后崩潰恢復(fù)過程中不能直接應(yīng)用redo log ,innodb發(fā)現(xiàn)break page后實(shí)際上會報錯。

注:mysql的邏輯日志、物理日志與物理邏輯日志

物理邏輯日志不是完全冪等的,這取決于重做日志類型,對于INSERT產(chǎn)生的日志其不是冪等的。

2. double write

2.1 簡述

為了解決頁斷裂(partial write)問題,InnoDB實(shí)現(xiàn)了double write機(jī)制。

簡單來說,在寫數(shù)據(jù)頁之前,先把這個數(shù)據(jù)頁寫到一個獨(dú)立的物理文件位置(ibdata),然后再寫到數(shù)據(jù)頁。這樣在宕機(jī)恢復(fù)的時候,如果數(shù)據(jù)頁損壞,那么在應(yīng)用redo log之前,需要通過該頁的副本來還原該頁,然后在進(jìn)行redo log重做。這就是doublewrite。doublewrite技術(shù)帶給innodb存儲引擎的是數(shù)據(jù)頁的可靠性。

2.2 double write體系結(jié)構(gòu)和工作流程

double write由兩部分組成,一部分是InnoDB內(nèi)存中的double write buffer,大小為2MB,另一部分是物理磁盤上的ibdata,系統(tǒng)表空間中大小為2MB,共128個連續(xù)的Page(2*1024/16KB=128),即兩個分區(qū)(extend)一個段(segment)。其中120個頁用于批量刷新臟頁(如LRU LIST刷新與FLUSH LIST刷新這兩種刷新策略),另外8個頁用于單頁刷新(Single Page Flush)。做區(qū)分的原因是批量刷臟是后臺線程做的,不影響前臺線程。而單頁刷新是用戶線程發(fā)起的,需要盡快的刷臟頁并替換出一個空閑頁出來。

InnoDB刷新(寫出)緩沖區(qū)中的數(shù)據(jù)頁時采用的是一次寫多個頁的方式:

  1. 多個頁就可以先順序?qū)懭氲絛ouble write buffer,并調(diào)用fsync()保證這些數(shù)據(jù)被刷新到double write磁盤(ibdata)。
  2. 然后數(shù)據(jù)頁調(diào)用fsync()被刷新到實(shí)際存儲位置;
  3. 故障恢復(fù)時InnoDB檢查double write Buffer與數(shù)據(jù)頁原存儲位置的內(nèi)容,若double write頁處于頁斷裂狀態(tài),則簡單的丟棄;若數(shù)據(jù)頁不一致,則從double write頁還原。
double write 流程.png

由于double write頁落盤與數(shù)據(jù)頁落盤在不同的時間點(diǎn),不會出現(xiàn)double write頁和數(shù)據(jù)頁同時發(fā)生斷裂的情況,因此doublewrite技術(shù)可以解決頁斷裂問題,進(jìn)而保證了重做日志能順利進(jìn)行,數(shù)據(jù)庫能恢復(fù)到一致的狀態(tài)。

2.3 double write性能損耗

表面看上去,每個頁面都寫了2遍,會非常影響性能。但實(shí)際上,由于所寫的頁面會先緩存到內(nèi)存中,因此每一部分緩存空間在滿了之后才會真正的寫入文件。并且double write是一個連續(xù)的存儲空間,所以硬盤在寫數(shù)據(jù)的時候是順序?qū)懀皇请S機(jī)寫,這樣性能很高。doublewrite有效利用這個特點(diǎn),所以降低并不會相差1倍,經(jīng)過測試,大概5-10%左右。當(dāng)然,這是針對普通磁盤。對于目前比較流行的SSD來說,隨機(jī)寫已經(jīng)不是問題,性能影響可能更小。

2.4 double write的配置

double write并不是什么特性或優(yōu)點(diǎn),它只是一個被動解決方案而已。這個問題的本質(zhì)就是磁盤在寫入時,都是以512字節(jié)為單位,不能保證MySQL數(shù)據(jù)頁面16KB的一次性原子寫,所以才有可能產(chǎn)生頁面斷裂的問題。而目前有些廠商從硬件驅(qū)動層面做了優(yōu)化,可以保證16KB(或其他配置)數(shù)據(jù)的原子性寫入。如果真是這樣,那么兩次寫就完全沒有必要了,取消兩次寫,才是最終級優(yōu)化。

mysql的double write默認(rèn)開啟,參數(shù)skip_innodb_doublewrite雖然可以禁止使用doublewrite功能,但還是強(qiáng)烈建議大家使用doublewrite,避免部分寫失效問題。

mysql> show variables like '%double%';
+--------------------+-------+
| Variable_name      | Value |
+--------------------+-------+
| innodb_doublewrite | ON    |
+--------------------+-------+
1 row in set (0.00 sec)

2.5 InnoDB能否通過其他方式解決partial write

其實(shí)保證mysql數(shù)據(jù)頁面(16KB)原子性的寫入到磁盤(每次512字節(jié))中,就可以解決partial write。

  1. 如果系統(tǒng)表空間文件(“ibdata文件”)位于支持原子寫入的Fusion-io設(shè)備上,就能避免partial write ;
  2. 阿里云polardb,在底層分布式文件系統(tǒng)PolarFS能提供頁大小(如16)KB小的原子寫入,無需double write機(jī)制來避免partial write。

推薦閱讀

MySQL InnoDB特性:兩次寫(DoubleWrite)

頁斷裂(partial write)與doublewrite技術(shù)

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容