寫緩衝(change buffer)

原文鏈接:https://mp.weixin.qq.com/s?__biz=MjM5ODYxMDA5OQ==&mid=2651962467&idx=1&sn=899ea157b0fc6f849ec80a4d055a309b&chksm=bd2d09bf8a5a80a972a2e16a190ed7dffe03f89015ead707bdfcc5aeb8388fb278f397c125f1&scene=21#wechat_redirect

寫緩衝(change buffer)

在這裏插入圖片描述
(1)MySQL數據存儲包含內存與磁盤兩個部分;

(2)內存緩衝池(buffer pool)以頁爲單位,緩存最熱的數據頁(data page)與索引頁(index page);

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

毫無疑問,對於讀請求,緩衝池能夠減少磁盤IO,提升性能。問題來了,那寫請求呢?
情況一
假如要修改頁號爲4的索引頁,而這個頁正好在緩衝池內。
在這裏插入圖片描述
如上圖序號1-2:

(1)直接修改緩衝池中的頁,一次內存操作;

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

這樣的效率是最高的。

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

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

(2)緩衝池LRU數據淘汰,會將“髒頁”刷回磁盤;

(3)數據庫異常奔潰,能夠從redo log中恢復數據;

什麼時候緩衝池中的頁,會刷到磁盤上呢?
定期刷磁盤,而不是每次刷磁盤,能夠降低磁盤IO,提升MySQL的性能。

批量寫,是常見的優化手段。

情況二
假如要修改頁號爲40的索引頁,而這個頁正好不在緩衝池內。
在這裏插入圖片描述
此時麻煩一點,如上圖需要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,提升數據庫性能。

InnoDB加入寫緩衝優化,上文“情況二”流程會有什麼變化?
假如要修改頁號爲40的索引頁,而這個頁正好不在緩衝池內。
在這裏插入圖片描述
加入寫緩衝優化後,流程優化爲:
(1)在寫緩衝中記錄這個操作,一次內存操作;

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

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

可以看到,40這一頁,並沒有加載到緩衝池中。

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

(1)數據庫異常奔潰,能夠從redo log中恢復數據;

(2)寫緩衝不只是一個內存結構,它也會被定期刷盤到寫緩衝系統表空間;

(3)數據讀取時,有另外的流程,將數據合併到緩衝池;

不妨設,稍後的一個時間,有請求查詢索引頁40的數據。
在這裏插入圖片描述
此時的流程如序號1-3:
(1)載入索引頁,緩衝池未命中,這次磁盤IO不可避免;

(2)從寫緩衝讀取相關信息;

(3)恢復索引頁,放到緩衝池LRU裏;

可以看到,40這一頁,在真正被讀取時,纔會被加載到緩衝池中。

還有一個遺漏問題,爲什麼寫緩衝優化,僅適用於非唯一普通索引頁呢?
如果索引設置了唯一(unique)屬性,在進行修改操作時,InnoDB必須進行唯一性檢查。也就是說,索引頁即使不在緩衝池,磁盤上的頁讀取無法避免(否則怎麼校驗是否唯一?),此時就應該直接把相應的頁放入緩衝池再進行修改,而不應該再寫緩衝。

除了數據頁被訪問,還有哪些場景會觸發刷寫緩衝中的數據呢?

還有這麼幾種情況,會刷寫緩衝中的數據:
(1)有一個後臺線程,會認爲數據庫空閒時;

(2)數據庫緩衝池不夠用時;

(3)數據庫正常關閉時;

(4)redo log寫滿時;

幾乎不會出現redo log寫滿,此時整個數據庫處於無法寫入的不可用狀態。

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

先說什麼時候不適合,如上文分析,當:
(1)數據庫都是唯一索引;

(2)或者,寫入一個數據後,會立刻讀取它;

這兩類場景,在寫操作進行時(進行後),本來就要進行進行頁讀取,本來相應頁面就要入緩衝池,此時寫緩存反倒成了負擔,增加了複雜度。

什麼時候適合使用寫緩衝,如果:
(1)數據庫大部分是非唯一索引;

(2)業務是寫多讀少,或者不是寫後立刻讀取;

可以使用寫緩衝,將原本每次寫入都需要進行磁盤IO的SQL,優化定期批量寫磁盤。

上述原理,對應InnoDB裏哪些參數?
有兩個比較重要的參數。
在這裏插入圖片描述
參數:innodb_change_buffer_max_size
介紹:配置寫緩衝的大小,佔整個緩衝池的比例,默認值是25%,最大值是50%。
寫多讀少的業務,才需要調大這個值,讀多寫少的業務,25%其實也多了。

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

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章