寫緩衝(change buffer),此次完全懂了!!!

上篇《緩衝池(buffer pool),完全懂了!》介紹了InnoDB緩衝池的工做原理。算法

簡單回顧一下:
寫緩衝(change buffer),此次完全懂了!!!
(1)MySQL數據存儲包含內存與磁盤兩個部分;
(2)內存緩衝池(buffer pool)以頁爲單位,緩存最熱的數據頁(data page)與索引頁(index page);
(3)InnoDB以變種LRU算法管理緩衝池,並可以解決「預讀失效」與「緩衝池污染」的問題;
畫外音:細節詳見《緩衝池(buffer pool),完全懂了!》。shell

毫無疑問,對於讀請求,緩衝池可以減小磁盤IO,提高性能。問題來了,那寫請求呢?數據庫

狀況一

假如要修改頁號爲4的索引頁,而這個頁正好在緩衝池內。
寫緩衝(change buffer),此次完全懂了!!!
如上圖序號1-2:
(1)直接修改緩衝池中的頁,一次內存操做;
(2)寫入redo log,一次磁盤順序寫操做;
這樣的效率是最高的。
畫外音:像寫日誌這種順序寫,每秒幾萬次沒問題。緩存

是否會出現一致性問題呢?

並不會。
(1)讀取,會命中緩衝池的頁;
(2)緩衝池LRU數據淘汰,會將「髒頁」刷回磁盤;
(3)數據庫異常奔潰,可以從redo log中恢復數據;架構

何時緩衝池中的頁,會刷到磁盤上呢?

按期刷磁盤,而不是每次刷磁盤,可以下降磁盤IO,提高MySQL的性能。
畫外音:批量寫,是常見的優化手段。ide

狀況二

假如要修改頁號爲40的索引頁,而這個頁正好不在緩衝池內。
寫緩衝(change buffer),此次完全懂了!!!
此時麻煩一點,如上圖須要1-3:
(1)先把須要爲40的索引頁,從磁盤加載到緩衝池,一次磁盤隨機讀操做;
(2)修改緩衝池中的頁,一次內存操做;
(3)寫入redo log,一次磁盤順序寫操做;性能

沒有命中緩衝池的時候,至少產生一次磁盤IO,對於寫多讀少的業務場景,是否還有優化的空間呢?優化

這便是InnoDB考慮的問題,又是本文將要討論的寫緩衝(change buffer)。
畫外音:從名字容易看出,寫緩衝是下降磁盤IO,提高數據庫寫性能的一種機制。線程

什麼是InnoDB的寫緩衝?

在MySQL5.5以前,叫插入緩衝(insert buffer),只針對insert作了優化;如今對delete和update也有效,叫作寫緩衝(change buffer)。日誌

它是一種應用在非惟一普通索引頁(non-unique secondary index page)不在緩衝池中,對頁進行了寫操做,並不會馬上將磁盤頁加載到緩衝池,而僅僅記錄緩衝變動(buffer changes),等將來數據被讀取時,再將數據合併(merge)恢復到緩衝池中的技術。寫緩衝的目的是下降寫操做的磁盤IO,提高數據庫性能。
畫外音:R了狗了,這個句子,好長。

InnoDB加入寫緩衝優化,上文「狀況二」流程會有什麼變化?

假如要修改頁號爲40的索引頁,而這個頁正好不在緩衝池內。
寫緩衝(change buffer),此次完全懂了!!!
加入寫緩衝優化後,流程優化爲:
(1)在寫緩衝中記錄這個操做,一次內存操做;
(2)寫入redo log,一次磁盤順序寫操做;
其性能與,這個索引頁在緩衝池中,相近。
畫外音:能夠看到,40這一頁,並無加載到緩衝池中。

是否會出現一致性問題呢?

也不會。
(1)數據庫異常奔潰,可以從redo log中恢復數據;
(2)寫緩衝不僅是一個內存結構,它也會被按期刷盤到寫緩衝系統表空間;
(3)數據讀取時,有另外的流程,將數據合併到緩衝池;

不妨設,稍後的一個時間,有請求查詢索引頁40的數據。
寫緩衝(change buffer),此次完全懂了!!!
此時的流程如序號1-3:
(1)載入索引頁,緩衝池未命中,此次磁盤IO不可避免;
(2)從寫緩衝讀取相關信息;
(3)恢復索引頁,放到緩衝池LRU裏;
畫外音:能夠看到,40這一頁,在真正被讀取時,纔會被加載到緩衝池中。

還有一個遺漏問題,爲何寫緩衝優化,僅適用於非惟一普通索引頁呢?
InnoDB裏,彙集索引(clustered index)和普通索引(secondary index)的異同,《1分鐘瞭解MyISAM與InnoDB的索引差別》有詳盡的敘述,再也不展開。

若是索引設置了惟一(unique)屬性,在進行修改操做時,InnoDB必須進行惟一性檢查。也就是說,索引頁即便不在緩衝池,磁盤上的頁讀取沒法避免(不然怎麼校驗是否惟一?),此時就應該直接把相應的頁放入緩衝池再進行修改,而不該該再整寫緩衝這個幺蛾子。

除了數據頁被訪問,還有哪些場景會觸發刷寫緩衝中的數據呢?
還有這麼幾種狀況,會刷寫緩衝中的數據:
(1)有一個後臺線程,會認爲數據庫空閒時;
(2)數據庫緩衝池不夠用時;
(3)數據庫正常關閉時;
(4)redo log寫滿時;
畫外音:幾乎不會出現redo log寫滿,此時整個數據庫處於沒法寫入的不可用狀態。

什麼業務場景,適合開啓InnoDB的寫緩衝機制?

先說何時不適合,如上文分析,當:
(1)數據庫都是惟一索引;
(2)或者,寫入一個數據後,會馬上讀取它;
這兩類場景,在寫操做進行時(進行後),原本就要進行進行頁讀取,原本相應頁面就要入緩衝池,此時寫緩存反倒成了負擔,增長了複雜度。

何時適合使用寫緩衝,若是:
(1)數據庫大部分是非惟一索引;
(2)業務是寫多讀少,或者不是寫後馬上讀取;
可使用寫緩衝,將本來每次寫入都須要進行磁盤IO的SQL,優化按期批量寫磁盤。
畫外音:例如,帳單流水業務。

上述原理,對應InnoDB裏哪些參數?

有兩個比較重要的參數。
寫緩衝(change buffer),此次完全懂了!!!
參數:innodb_change_buffer_max_size
介紹:配置寫緩衝的大小,佔整個緩衝池的比例,默認值是25%,最大值是50%。
畫外音:寫多讀少的業務,才須要調大這個值,讀多寫少的業務,25%其實也多了。

參數:innodb_change_buffering
介紹:配置哪些寫操做啓用寫緩衝,能夠設置成all/none/inserts/deletes等。

但願你們有收穫,思路比結論重要。
寫緩衝(change buffer),此次完全懂了!!!架構師之路-分享技術思路相關推薦:《6條shell小技巧,讓腳本更專業 | 1分鐘系列》《MyISAM與InnoDB的索引差別 | 1分鐘系列》《緩衝池(buffer pool),此次完全懂了!!!》《學會聆聽,職場最重要的事情!!!》