天天看點

寫緩沖(change buffer),這次徹底懂了!!!

上篇

《緩沖池(buffer pool),徹底懂了!》

介紹了InnoDB緩沖池的工作原理。

簡單回顧一下:

寫緩沖(change buffer),這次徹底懂了!!!

(1)MySQL資料存儲包含記憶體與磁盤兩個部分;

(2)記憶體緩沖池(buffer pool)以頁為機關,緩存最熱的資料頁(data page)與索引頁(index page);

(3)InnoDB以變種LRU算法管理緩沖池,并能夠解決“預讀失效”與“緩沖池污染”的問題;

畫外音:細節詳見

毫無疑問,對于讀請求,緩沖池能夠減少磁盤IO,提升性能。問題來了,那寫請求呢?

情況一

假如要修改頁号為4的索引頁,而這個頁正好在緩沖池内。

寫緩沖(change buffer),這次徹底懂了!!!

如上圖序号1-2:

(1)直接修改緩沖池中的頁,一次記憶體操作;

(2)寫入redo log,一次磁盤順序寫操作;

這樣的效率是最高的。

畫外音:像寫日志這種順序寫,每秒幾萬次沒問題。

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

并不會。

(1)讀取,會命中緩沖池的頁;

(2)緩沖池LRU資料淘汰,會将“髒頁”刷回磁盤;

(3)資料庫異常奔潰,能夠從redo log中恢複資料;

什麼時候緩沖池中的頁,會刷到磁盤上呢?

定期刷磁盤,而不是每次刷磁盤,能夠降低磁盤IO,提升MySQL的性能。

畫外音:批量寫,是常見的優化手段。

情況二

假如要修改頁号為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加入寫緩沖優化,上文“情況二”流程會有什麼變化?

加入寫緩沖優化後,流程優化為:

(1)在寫緩沖中記錄這個操作,一次記憶體操作;

其性能與,這個索引頁在緩沖池中,相近。

畫外音:可以看到,40這一頁,并沒有加載到緩沖池中。

寫緩沖(change buffer),這次徹底懂了!!!

也不會。

(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等。

希望大家有收獲,思路比結論重要。

本文轉自“架構師之路”公衆号,58沈劍提供。