您好,登錄后才能下訂單哦!
本篇內(nèi)容介紹了“Innodb關(guān)鍵特性之什么是doublewrite”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!
一、經(jīng)典Partial page write問題
介紹double write之前我們有必要了解partial page write(部分頁失效)問題。
InnoDB的Page Size一般是16KB,其數(shù)據(jù)校驗(yàn)也是針對(duì)這16KB來計(jì)算的,將數(shù)據(jù)寫入到磁盤是以Page為單位進(jìn)行操作的。我們知道,由于文件系統(tǒng)對(duì)一次大數(shù)據(jù)頁(例如InnoDB的16KB)大多數(shù)情況下不是原子操作,這意味著如果服務(wù)器宕機(jī)了,可能只做了部分寫入。16K的數(shù)據(jù),寫入4K時(shí),發(fā)生了系統(tǒng)斷電/os crash ,只有一部分寫是成功的,這種情況下就是partial page write問題。
有經(jīng)驗(yàn)的DBA可能會(huì)想到,如果發(fā)生寫失效,MySQL可以根據(jù)redo log進(jìn)行恢復(fù)。這是一個(gè)辦法,但是必須清楚地認(rèn)識(shí)到,redo log中記錄的是對(duì)頁的物理修改,如偏移量800,寫’aaaa’記錄。如果這個(gè)頁本身已經(jīng)發(fā)生了損壞,再對(duì)其進(jìn)行重做是沒有意義的。MySQL在恢復(fù)的過程中檢查page的checksum,checksum就是檢查page的最后事務(wù)號(hào),發(fā)生partial page write問題時(shí),page已經(jīng)損壞,找不到該page中的事務(wù)號(hào)。在InnoDB看來,這樣的數(shù)據(jù)頁是無法通過checksum驗(yàn)證的,就無法恢復(fù)。即時(shí)我們強(qiáng)制讓其通過驗(yàn)證,也無法從崩潰中恢復(fù),因?yàn)楫?dāng)前InnoDB存在的一些日志類型,有些是邏輯操作,并不能做到冪等。
為了解決這個(gè)問題,InnoDB實(shí)現(xiàn)了double write buffer,簡單來說,就是在寫數(shù)據(jù)頁之前,先把這個(gè)數(shù)據(jù)頁寫到一塊獨(dú)立的物理文件位置(ibdata),然后再寫到數(shù)據(jù)頁。這樣在宕機(jī)重啟時(shí),如果出現(xiàn)數(shù)據(jù)頁損壞,那么在應(yīng)用redo log之前,需要通過該頁的副本來還原該頁,然后再進(jìn)行redo log重做,這就是double write。double write技術(shù)帶給innodb存儲(chǔ)引擎的是數(shù)據(jù)頁的可靠性,下面對(duì)doublewrite技術(shù)進(jìn)行解析,讓大家充分理解double write是如何做到保障數(shù)據(jù)頁的可靠性。
二、double write體系結(jié)構(gòu)及工作流程
double write由兩部分組成,一部分是InnoDB內(nèi)存中的double write buffer,大小為2M,另一部分是物理磁盤上ibdata系統(tǒng)表空間中大小為2MB,共128個(gè)連續(xù)的Page,既2個(gè)分區(qū)。其中120個(gè)用于批量寫臟,另外8個(gè)用于Single Page Flush。做區(qū)分的原因是批量刷臟是后臺(tái)線程做的,不影響前臺(tái)線程。而Single page flush是用戶線程發(fā)起的,需要盡快的刷臟并替換出一個(gè)空閑頁出來。
對(duì)于批量刷臟,每次找到一個(gè)可做flush的page,對(duì)其持有S lock,然后將該page拷貝到dblwr中,當(dāng)dblwr滿后者一次批量刷臟結(jié)束時(shí),將dblwr中的page全部刷到ibdata中,注意這是同步寫操作;然后再喚醒后臺(tái)IO線程去寫數(shù)據(jù)頁。當(dāng)后臺(tái)IO線程完成寫操作后,會(huì)去更新dblwr中的計(jì)數(shù)以騰出空間,釋放block上的S鎖,完成寫入。
對(duì)于Single Page Flush,則做的是同步寫操作,在挑出一個(gè)可以刷臟的page后,先加入到dblwr中,刷到ibdata,然后寫到用戶表空間,完成后,會(huì)對(duì)該用戶表空間做一次fsync操作。
Single Page Flush在buffer pool中free page不夠時(shí)觸發(fā),通常由前臺(tái)線程發(fā)起,由于每次single page flush都會(huì)導(dǎo)致一次fsync操作,在大并發(fā)負(fù)載下,如果大量線程去做flush,很顯然會(huì)產(chǎn)生嚴(yán)重的性能下降。Percona在5.6版本中做了優(yōu)化,可以選擇由后臺(tái)線程lru manager來做預(yù)刷,避免用戶線程陷入其中。
如果發(fā)生了極端情況(斷電),InnoDB再次啟動(dòng)后,發(fā)現(xiàn)了一個(gè)Page數(shù)據(jù)已經(jīng)損壞,那么此時(shí)就可以從double write buffer中進(jìn)行數(shù)據(jù)恢復(fù)了。
double write工作流程如下:
當(dāng)一系列機(jī)制(main函數(shù)觸發(fā)、checkpoint等)觸發(fā)數(shù)據(jù)緩沖池中的臟頁進(jìn)行刷新到data file的時(shí)候,并不直接寫磁盤,而是會(huì)通過memcpy函數(shù)將臟頁先復(fù)制到內(nèi)存中的double write buffer,之后通過double write buffer再分兩次、每次1MB順序?qū)懭牍蚕肀砜臻g的物理磁盤上。然后馬上調(diào)用fsync函數(shù),同步臟頁進(jìn)磁盤上。由于在這個(gè)過程中,double write頁的存儲(chǔ)時(shí)連續(xù)的,因此寫入磁盤為順序?qū)?,性能很高;完成double write后,再將臟頁寫入實(shí)際的各個(gè)表空間文件,這時(shí)寫入就是離散的了。各模塊協(xié)作情況如下圖(第一步應(yīng)為臟頁產(chǎn)生的redo記錄log buffer,然后log buffer寫入redo log file,為簡化次要步驟直接連線表示):
查看doublewrite工作情況,可以執(zhí)行命令:
mysql>show status like '%InnoDB_dblwr%' +----------------------------+-----------------+ | Variable_name | Value | +----------------------------+-----------------+ | Innodb_dblwr_pages_written | 216261751 | | Innodb_dblwr_writes | 43307580 | +----------------------------+-----------------+
以上數(shù)據(jù)顯示,double write一共寫了 61932183個(gè)頁,一共寫了15237891次,從這組數(shù)據(jù)我們可以分析,之前講過在開啟double write后,每次臟頁刷新必須要先寫double write,而double write存在于磁盤上的是兩個(gè)連續(xù)的區(qū),每個(gè)區(qū)由連續(xù)的頁組成,一般情況下一個(gè)區(qū)最多有64個(gè)頁,所以一次IO寫入應(yīng)該可以最多寫64個(gè)頁。而根據(jù)以上我這個(gè)系統(tǒng)Innodb_dblwr_pages_written與Innodb_dblwr_writes的比例來看,一次大概在4個(gè)頁左右,遠(yuǎn)遠(yuǎn)還沒到64,所以從這個(gè)角度也可以看出,系統(tǒng)寫入壓力并不高。
如果操作系統(tǒng)在將頁寫入磁盤的過程中發(fā)送了崩潰,在恢復(fù)過程中,InnoDB存儲(chǔ)引擎可以從工序表空間中的double write中找到該頁的副本,將其復(fù)制到表空間文件,再應(yīng)用redo log。下面顯示了一個(gè)由double write進(jìn)行恢復(fù)的過程:
090924 11:36:32 mysqld restarted
090924 11:26:33 InnoDB: Database was not shut down normally!
InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Crash recovery may have faild for some .ibd files!
InnoDB: Restoring possible half-written data pages from the doublewrite.
InnoDB: buffer...
三、double write的缺點(diǎn)
dblwr位于共享表空間上的double write buffer實(shí)際上也是一個(gè)文件,引入了一次額外寫的開銷,每個(gè)數(shù)據(jù)頁都被要求寫兩次。由于需要大量的fsync操作,所以它會(huì)降低MySQL的整體性能,但是并不會(huì)降低到原來的50%。這主要是因?yàn)椋?/p>
1) double write是一個(gè)連接的存儲(chǔ)空間,所以硬盤在寫數(shù)據(jù)的時(shí)候是順序?qū)懀皇请S機(jī)寫,這樣性能更高。
2) 將數(shù)據(jù)從double write buffer寫到真正的segment中的時(shí)候,系統(tǒng)會(huì)自動(dòng)合并連接空間刷新的方式,每次可以刷新多個(gè)pages。
double write默認(rèn)開啟,參數(shù)skip_innodb_doublewrite雖然可以禁止使用double write功能,但還是強(qiáng)烈建議大家使用double write。避免部分寫失效問題,當(dāng)然,如果你的數(shù)據(jù)表空間放在本身就提供了部分寫失效防范機(jī)制的文件系統(tǒng)上,如ZFS/FusionIO/DirectFS文件系統(tǒng),在這種情況下,就可以不開啟doublewrite了
四、double write在恢復(fù)的時(shí)候是如何工作的
如果是寫double write buffer本身失敗,那么這些數(shù)據(jù)不會(huì)被寫到磁盤,InnoDB此時(shí)會(huì)從磁盤載入原始的數(shù)據(jù),然后通過InnoDB的事務(wù)日志來計(jì)算出正確的數(shù)據(jù),重新寫入到double write buffer。
如果double write buffer寫成功的話,但是寫磁盤失敗,InnoDB就不用通過事務(wù)日志來計(jì)算了,而是直接用buffer的數(shù)據(jù)再寫一遍。如上圖中顯示,在恢復(fù)的時(shí)候,InnoDB直接比較頁面的checksum,如果不對(duì)的話,Innodb存儲(chǔ)引擎可以從共享表空間的double write中找到該頁的一個(gè)最近的副本,將其復(fù)制到表空間文件,再應(yīng)用redo log,就完成了恢復(fù)過程。因?yàn)橛懈北舅砸膊粨?dān)心表空間中數(shù)據(jù)頁是否損壞,但I(xiàn)nnoDB的恢復(fù)通常需要較長的時(shí)間。
“Innodb關(guān)鍵特性之什么是doublewrite”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。