新聞中心
?昨天剛剛下飛機(jī)就接到電話(huà)說(shuō)一個(gè)長(zhǎng)輩去世,今天一早坐高鐵回老家參加喪禮。所以這篇前兩天寫(xiě)了個(gè)頭的文章今天是在高鐵上完成的,有些實(shí)驗(yàn)不方便做,就只能簡(jiǎn)化了。

創(chuàng)新互聯(lián)是專(zhuān)業(yè)的劍河網(wǎng)站建設(shè)公司,劍河接單;提供網(wǎng)站建設(shè)、網(wǎng)站設(shè)計(jì),網(wǎng)頁(yè)設(shè)計(jì),網(wǎng)站設(shè)計(jì),建網(wǎng)站,PHP網(wǎng)站建設(shè)等專(zhuān)業(yè)做網(wǎng)站服務(wù);采用PHP框架,可快速的進(jìn)行劍河網(wǎng)站開(kāi)發(fā)網(wǎng)頁(yè)制作和功能擴(kuò)展;專(zhuān)業(yè)做搜索引擎喜愛(ài)的網(wǎng)站,專(zhuān)業(yè)的做網(wǎng)站團(tuán)隊(duì),希望更多企業(yè)前來(lái)合作!
前兩天一個(gè)朋友說(shuō)PG的熱塊沖突比Oracle更容易產(chǎn)生,并會(huì)產(chǎn)生比較嚴(yán)重的性能問(wèn)題,特別是當(dāng)系統(tǒng)中的一些大型的熱表存在大量UPDATE操作的時(shí)候。確實(shí)PG的ASTORE機(jī)制使用多個(gè)版本的TUPLE來(lái)保存某一行的歷史版本,這種機(jī)制導(dǎo)致了PG的SHARED BUFFERS的鎖會(huì)比較復(fù)雜。和朋友討論問(wèn)題后,我根據(jù)以前學(xué)習(xí)過(guò)的一些關(guān)于PG BUFFER的知識(shí),畫(huà)了一個(gè)思維導(dǎo)圖。
PG的BUFFER 居然和三種鎖有關(guān),一種是SPINLOCK,用于管理BUFFER的空閑鏈的,如果要分配空閑緩沖區(qū),則需要通過(guò)一個(gè)SPINLOCK(Buffer Strategy Lock)來(lái)獲得。另外兩類(lèi)異類(lèi)是我們比較容易理解的用于保護(hù)PG內(nèi)存結(jié)構(gòu)的鎖LWLOCK。最后異類(lèi)就比較令人費(fèi)解了,如果我們看PG的等待事件,里面有一類(lèi)獨(dú)特的分類(lèi)。
這類(lèi)等待事件稱(chēng)為BufferPin,而這個(gè)等待事件大類(lèi)里面只有一種等待事件,BufferPIN。這些鎖之間都是什么關(guān)系呢?我們可以看上面的思維導(dǎo)圖。
比如我們模擬一個(gè)BUFFER的一生,首先當(dāng)要訪(fǎng)問(wèn)某個(gè)PG PAGE的時(shí)候,先要從FREE的BUFFER中找到一個(gè),此時(shí)需要一個(gè)SPINLOCK(Buffer Strategy Lock),然后從FREELIST上取下BUFFER,準(zhǔn)備給新的PAGE使用,此時(shí)我們需要PIN住這個(gè)BUFFER,使之不能被BUFFER替換等操作使用。
然后需要申請(qǐng)一個(gè)BUFFER CONTENT鎖,來(lái)修改這個(gè)BUFFER,通過(guò)加buffer header lock來(lái)修改BUFFER頭上的訪(fǎng)問(wèn)指針計(jì)數(shù)器等信息。然后就要開(kāi)始讀取PAGE的IO操作了,此時(shí)需要獲得一個(gè)BUFFER IO鎖,指示該BUFFER正在進(jìn)行IO操作,從而避免在同一個(gè)BUFFER上的多個(gè)IO并發(fā)進(jìn)行。
IO結(jié)束后,這個(gè)BUFFER中已經(jīng)包含了我們所需要的PAGE,此時(shí)我們需要把這個(gè)BUFFER加入到HASH CHAINS里,此時(shí)就需要一個(gè)buffer mapping鎖,從而便于今后BUFFER掃描定位,這個(gè)鎖有點(diǎn)類(lèi)似Oracle的CBC閂鎖,也是多個(gè)鎖分區(qū)管理的,PG使用多個(gè)分區(qū)來(lái)提高并行效率。
下面我們來(lái)看一個(gè)例子:
此時(shí)我們?cè)诹硗庖粋€(gè)會(huì)話(huà)里查看一下BUFFER PIN的情況:
可以看到一個(gè)BUFFER是被PIN住了。此時(shí)我們?nèi)绻麍?zhí)行VACCUM會(huì)發(fā)生什么呢?
可以看到VACUUM跳過(guò)了被PIN住的BUFFER,因?yàn)獒槍?duì)PIN住的BUFFER,PG無(wú)法對(duì)其中的PAGE做VACUUM這樣的不兼容的操作。
此時(shí)如果做不兼容的vacuum freeze操作就會(huì)被鎖住,要等待BUFFER PIN被移除。BUFFER PIN是一個(gè)共享鎖,不會(huì)阻塞同一個(gè)PAGE上的并發(fā)寫(xiě)操作,不過(guò)這個(gè)共享鎖還是會(huì)產(chǎn)生一些并發(fā)互斥的操作,比如會(huì)阻止VACUUM對(duì)這個(gè)PAGE進(jìn)行回收整理操作,使VACUUM操作跳過(guò)這個(gè)PAGE,會(huì)阻止FREEZE操作,直到PIN住該BUFFER的所有鎖全部移除。
因?yàn)镻G數(shù)據(jù)庫(kù)采用的是APPEND STORE模式,因此一個(gè)行的UPDATE會(huì)產(chǎn)生多個(gè)行副本,這對(duì)于PG的數(shù)據(jù)行的訪(fǎng)問(wèn)操作來(lái)說(shuō)會(huì)增加額外的成本,在這里我們還需要考慮索引訪(fǎng)問(wèn)的成本問(wèn)題。如果這些記錄副本都存儲(chǔ)在同一個(gè)PAGE里,那么處理起來(lái)成本相對(duì)還比較低,PG采用HOT來(lái)降低索引的維護(hù)和訪(fǎng)問(wèn)成本。
如果多個(gè)TUPLE是分布在多個(gè)PAGE中,那么這個(gè)成本的增加就不可避免了。如果我們的應(yīng)用系統(tǒng)中的某些表上的UPDATE十分頻繁,那么這種額外的成本就會(huì)更大。再加上PG在訪(fǎng)問(wèn)數(shù)據(jù)時(shí)的各種鎖的開(kāi)銷(xiāo),這個(gè)疊加成本就更大了。
以VACUUM為例,如果我們的應(yīng)用出現(xiàn)了BUG,打開(kāi)一個(gè)CURSOR后忘記關(guān)閉了,或者一個(gè)死會(huì)話(huà)沒(méi)有釋放相關(guān)的CURSOR,那么某個(gè)或者某些BUFFER會(huì)被長(zhǎng)時(shí)間PIN住,VACUUM每次都會(huì)跳過(guò)這些PAGE,時(shí)間長(zhǎng)了,就會(huì)引發(fā)一些莫名其妙的問(wèn)題。
希望今天看了這篇文章后,我們?cè)偃タ碢G等待事件中關(guān)于BUFFER的事件,可以更準(zhǔn)確的了解到哪些等待事件代表什么含義,從而可以更好的定位問(wèn)題。
正是因?yàn)镻G的這種特性,在使用PG數(shù)據(jù)庫(kù)的時(shí)候我們不能像使用Oracle那樣肆無(wú)忌憚,如果做UPDATE操作,盡可能優(yōu)化應(yīng)用邏輯,讓一條數(shù)據(jù)的UPDATE次數(shù)盡可能的減少。另外對(duì)于UPDATE十分頻繁的表,或者需要對(duì)很多列進(jìn)行UPDATE的寬表,其表的FILLFACTOR參數(shù)要適當(dāng)減少,盡可能利用HOT來(lái)優(yōu)化訪(fǎng)問(wèn)性能。另外,如果某張經(jīng)常UPDATE的寬表是可以分拆的,那么盡可能把這張表分拆為多張表。
我和很多使用PG數(shù)據(jù)庫(kù)的人交流過(guò),有些人就說(shuō)PG很好用,我們用了PG后系統(tǒng)一直都很穩(wěn)定。有些朋友就說(shuō)經(jīng)常踩坑。實(shí)際上很多數(shù)據(jù)庫(kù)都是有各種各樣的坑的,如果你知道坑的存在,那就不容易踩坑了。有坑不可怕,不知道前面有坑才更可怕。
文章題目:聊聊PG的Buffer相關(guān)鎖,你懂了嗎?
文章地址:http://www.5511xx.com/article/cciscop.html


咨詢(xún)
建站咨詢(xún)
