華為云計(jì)算 云知識(shí) GaussDB(for MySQL) bufferpool緩存策略介紹
GaussDB(for MySQL) bufferpool緩存策略介紹

華為云GaussDB(for MySQL)是華為云自主研發(fā)的最新一代 云原生 數(shù)據(jù)庫,采用計(jì)算存儲(chǔ)分離、日志即數(shù)據(jù)的架構(gòu)設(shè)計(jì)。通過IO卸載、日志壓縮合并、批量處理、軟硬件垂直整合等技術(shù),使 數(shù)據(jù)庫 性能方面有了大幅提升。同時(shí)存儲(chǔ)層采用多副本,多AZ部署,增強(qiáng)數(shù)據(jù)可靠性。具備極致可靠、極致性價(jià)比、多為擴(kuò)展、完全可信等諸多特性。

GaussDB(for MySQL)采用了計(jì)算存儲(chǔ)分離、日志即數(shù)據(jù)的架構(gòu),一部分計(jì)算能力下推到存儲(chǔ)層。存儲(chǔ)層需要通過consolidation不斷將寫入的日志應(yīng)用到頁面上,從而將日志回收掉。另外SQL層從存儲(chǔ)層讀取頁面時(shí),也需要將日志回放到相應(yīng)的版本從而獲得對(duì)應(yīng)版本的頁面。如果每次都從磁盤讀取頁面,IO時(shí)延較大,這里將成為整個(gè)回放流程的瓶頸。

根據(jù)數(shù)據(jù)庫一貫的做法,我們需要一個(gè)緩存(bufferpool),把經(jīng)常訪問的頁面放在緩存中,從而加快頁面讀取的速度。但是存儲(chǔ)層能夠分配給bufferpool的資源非常有限,我們需要根據(jù)bufferpool的使用特點(diǎn)設(shè)計(jì)一個(gè)高效的緩存策略。

GaussDB(for MySQL)目前支持兩種緩存淘汰策略:LRU和LFU,這兩種淘汰算法都是改進(jìn)過的。

改進(jìn)的LFU算法

LFU在實(shí)現(xiàn)上采用unordered_map+list方式實(shí)現(xiàn),訪問數(shù)據(jù)時(shí),直接從unordered_map通過key在O(1)時(shí)間內(nèi)獲取到所需數(shù)據(jù)。為了避免數(shù)據(jù)在鏈表中頻繁移動(dòng),將鏈表按照引用計(jì)數(shù)分成多個(gè)區(qū)間,當(dāng)緩存命中時(shí),增加引用計(jì)數(shù),若引用計(jì)數(shù)仍落在原來的區(qū)間,保持?jǐn)?shù)據(jù)在鏈表中的位置不動(dòng),如果引用計(jì)數(shù)落入新的區(qū)間,將數(shù)據(jù)移動(dòng)到相應(yīng)位置。

為了避免一些頻繁訪問的數(shù)據(jù)后面不再訪問,但是引用計(jì)數(shù)很大,導(dǎo)致不能被淘汰,因此引入“老化”策略,每隔一段時(shí)間將引用計(jì)數(shù)值衰減一下,這樣就可以將一些引用計(jì)數(shù)較大,但是當(dāng)前不怎么訪問的數(shù)據(jù)淘汰出去。

一些被淘汰出去的數(shù)據(jù)我們還會(huì)在歷史記錄里面保留一段時(shí)間其對(duì)應(yīng)的引用計(jì)數(shù),下次該數(shù)據(jù)再次被加入緩存時(shí),可以“投胎轉(zhuǎn)世”,可以在上次的引用計(jì)數(shù)基礎(chǔ)上開始計(jì)數(shù)。這樣可以更精確的反應(yīng)數(shù)據(jù)被訪問的頻率。

LFU的緩存命中率較高,但是在“老化”的過程中需要對(duì)鏈表加鎖,這樣會(huì)阻塞其他地方的訪問。

改進(jìn)的LRU算法

與mysql的改進(jìn)LRU算法類似,也是將鏈表劃分為hot和cold兩個(gè)區(qū),數(shù)據(jù)第一次被加入時(shí)先放入cold區(qū),當(dāng)再次命中時(shí)移入hot區(qū)。淘汰時(shí)優(yōu)先淘汰cold區(qū)的數(shù)據(jù)。同時(shí)我們引入了一個(gè)lockfree的隊(duì)列,以免在flush page時(shí)對(duì)鏈表加鎖,增強(qiáng)緩沖操作的并發(fā)度。