我不認(rèn)為PG的Double Buffering是更優(yōu)秀的解決方案
關(guān)于PG在Shared buffers上的DOUBLE BUFFERING設(shè)計(jì),一直是爭(zhēng)議極多的。有一些搞PG的朋友認(rèn)為這是PG充分利用OS CACHE的一種特殊設(shè)計(jì),是PG數(shù)據(jù)庫(kù)設(shè)計(jì)中比較優(yōu)秀的地方。還有一些朋友則認(rèn)為這是一種過(guò)時(shí)的設(shè)計(jì),與當(dāng)前數(shù)據(jù)庫(kù)技術(shù)的發(fā)展潮流所相違背的。前些天有幾個(gè)朋友談到這個(gè)問(wèn)題,希望我寫(xiě)篇位置表達(dá)下我的觀點(diǎn)。
以我這些年做數(shù)據(jù)庫(kù)優(yōu)化的經(jīng)驗(yàn)來(lái)看,DOUBLE BUFFERING的設(shè)計(jì)如果算是一種技術(shù)上的進(jìn)步,在這一點(diǎn)上我一直是不太認(rèn)同的。眾所周知,現(xiàn)在幾乎所有的現(xiàn)代數(shù)據(jù)庫(kù)產(chǎn)品都是用AIO/DIO等方式來(lái)訪問(wèn)底層存儲(chǔ)系統(tǒng),只有PG目前還通過(guò)BUFFER/CACHE來(lái)讀取物理文件。隨著現(xiàn)代硬件的發(fā)展,BUFFERED IO的劣勢(shì)越來(lái)越顯現(xiàn)出來(lái)了。如果我們采用直接IO,繞過(guò)文件緩沖,那么就可以繞過(guò)BUFFER CACHE這一層,讓數(shù)據(jù)從文件到內(nèi)存更為直接,這會(huì)大幅提升OS到數(shù)據(jù)庫(kù)緩沖的數(shù)據(jù)交換的吞吐能力,同時(shí),因?yàn)镈MA等技術(shù)的使用,可以讓文件IO消耗的CPU資源更少,讓系統(tǒng)更為高效。這對(duì)于大型數(shù)據(jù)庫(kù)系統(tǒng)來(lái)說(shuō)絕對(duì)是十分必要的。PG數(shù)據(jù)庫(kù)越來(lái)越被用于大型OLTP系統(tǒng),直接IO替代BUFFERED IO肯定可以有效增加大型系統(tǒng)的并發(fā)IO能力。
另外一個(gè)方面,操作系統(tǒng)是無(wú)法充分理解數(shù)據(jù)庫(kù)的PAGE訪問(wèn)邏輯的,因此操作系統(tǒng)緩沖的效率比較shared buffers而言,要低的多。兩個(gè)分別由RDBMS和OS管理的分離的緩沖的效率肯定沒(méi)有一個(gè)獨(dú)立的數(shù)據(jù)庫(kù)緩沖高,這個(gè)應(yīng)該也是廣大研發(fā)人員的共識(shí)。不過(guò)這句話成立的前提是數(shù)據(jù)庫(kù)緩沖區(qū)被設(shè)計(jì)的十分高效,其LRU算法也被設(shè)計(jì)的十分合理。通過(guò)分析Oracle DB CACHE的算法的改進(jìn),我們也了解到為什么Oracle的DB CACHE能夠保持那么高的DB CACHE命中率了。
既然使用統(tǒng)一緩沖,消除DOUBLE BUFFERING那么重要,那么為什么PG還在堅(jiān)持使用DOUBLE BUFFERING呢?這個(gè)原因十分復(fù)雜,實(shí)際上最近這些年里,PG社區(qū)也在這方面做著不斷的努力。通過(guò)利用OS的AIO來(lái)替代當(dāng)前bufmgr.c中的BUFFERD IO操作,不過(guò)PG的IO堆棧太長(zhǎng)了,在大量的代碼中都存在和buffered io相關(guān)的內(nèi)容,再加上PG的文件結(jié)構(gòu)導(dǎo)致的預(yù)讀、連續(xù)塊訪問(wèn)的IO合并等問(wèn)題,要解決這個(gè)問(wèn)題并不容易。在IO路徑上,不僅僅需要修改bufmgr.c,在smgr.c,xlog.c,到底層的md.c,fd.c,甚至backend等模塊中都有大量IO相關(guān)的代碼需要修改。這些修改不僅僅是在調(diào)用文件IO時(shí)的函數(shù)調(diào)用的修改,還涉及到異步IO模式的修改,以及IO優(yōu)化、預(yù)讀等一系列的問(wèn)題。因此這部分的修改中左雖然已經(jīng)進(jìn)行了數(shù)年,但是要出現(xiàn)在正是發(fā)布的版本中,依然還需要一定的時(shí)間。這也成為PG代碼中的XID64之外的又一個(gè)老大難的問(wèn)題。
除此之外,在shared buffers的管理上,也需要做相應(yīng)的優(yōu)化,否則哪怕底層IO改為了AIO,buffer contention沖突也會(huì)讓一個(gè)大型的統(tǒng)一的數(shù)據(jù)庫(kù)緩沖的性能出現(xiàn)問(wèn)題。比如在Oracle上遇到的buffer busy waits等待,可能會(huì)在PG上放大,從而在高并發(fā)訪問(wèn)時(shí)引發(fā)嚴(yán)重的性能問(wèn)題。
舉個(gè)最簡(jiǎn)單的場(chǎng)景,那就是當(dāng)多個(gè)backend需要訪問(wèn)相同的一組PAGE的時(shí)候,PG目前的管理算法上海經(jīng)常會(huì)出現(xiàn)lwlock等待方面的超時(shí)等問(wèn)題。而Oracle從9i開(kāi)始已經(jīng)優(yōu)化了這方面的算法,當(dāng)多個(gè)并發(fā)的會(huì)話訪問(wèn)相同的block的時(shí)候,首先為這個(gè)BLOCK申請(qǐng)db cache的會(huì)話會(huì)PIN住這個(gè)BUFFER HEADER,然后開(kāi)始加載這個(gè)block(當(dāng)然也包含IO合并以及預(yù)讀,多塊讀方面的算法優(yōu)化),其他并發(fā)訪問(wèn)相同數(shù)據(jù)的會(huì)話就會(huì)等待“read by another session”,這個(gè)等待事件是Oracle 10g才開(kāi)始引入的,在9i中等待的依然是buffer busy waits,不過(guò)reason code(P3)參數(shù)是特殊的,從reason code可以缺別處這種特殊的熱塊沖突類(lèi)型。當(dāng)PG在這方面算法沒(méi)有做優(yōu)化之前,就無(wú)法區(qū)分這種情況,也就無(wú)法與AIO配合,達(dá)到最低成本的開(kāi)銷(xiāo)。
PG消除DOUBLE BUFFERING,在技術(shù)發(fā)展上來(lái)說(shuō),是必須要做的事情,只不過(guò)因?yàn)闅v史欠債還是較多,這方面的改造工作量很大,需要一些時(shí)間來(lái)完成。一旦PG完成這個(gè)改造,將可以充分利用AIO的能力,大幅提升PG數(shù)據(jù)庫(kù)讀寫(xiě)的能力,從而讓PG數(shù)據(jù)庫(kù)真正向大型關(guān)系型數(shù)據(jù)庫(kù)邁出一大步。目前我們有很多數(shù)據(jù)庫(kù)企業(yè)都是基于PG生態(tài)在做研發(fā),我也希望我們的數(shù)據(jù)庫(kù)廠商能夠在這方面多投入一些研發(fā),為PG社區(qū)解決這個(gè)難題提供一些中國(guó)方案。