Buffer Busy Waits是怎麼產生的?
哪些場景會產生Buffer Busy Waits
Buffer Busy Waits是Oracle 資料庫常見的一個等待,特別是在併發寫比較頻繁的環境裡。作為一個Oracle DBA,如果你從未遇到過Buffer Busy Waits等待,那麼你算不上一個真正的Oracle DBA。
產生這個等待的原因是,在記憶體級別,在同一時刻對同一記憶體塊進行讀寫產生了爭用。這裡我以2個程式對資料塊的操作為例,歸納出產生Buffer Busy Waits的場景:
-
寫寫,例如一個程式正在對記憶體塊做更改,此時另一個程式也要修改這個記憶體塊
-
寫讀,例如一個程式正在對記憶體塊做更改,另一個程式此時想要讀這個記憶體塊。你可能會問,oracle為什麼不去copy正在修改的塊構造CR塊,然後去讀構造出的CR塊,理由很簡單,記憶體塊正在寫(變化)的過程中去做copy,是一個不安全的動作。
按照字元的排列組合,還剩”讀讀“、”讀寫“兩個場景,這兩個場景都不會導致產生Buffer Busy Waits(這裡很重要的一個假設是2個程式),理由我們後面再給出,這裡按住不表。
為什麼要設計這個等待
Oracle為什麼要設計這個等待,這是個好問題,本篇文章也主要是為了解答這個疑問。
“為什麼”要比“是這樣做的”的更重要,前者講的是邏輯和洞見,後者描述的是過程和結果。
回答這個問題之前,首先設計一個場景,“假如沒有這個等待,讀寫資料塊是如何進行的”,當然這個場景是設計出來的,其實並不存在。
那我們開始,假設場景是這樣子的,我們要對一個資料塊做寫入操作,遵循如下步驟:
-
首先依據資料塊地址計算出(Hash演算法)該塊所在的Hash Bucket。
-
根據桶的編號,計算出保護這個桶的CBC Latch,然後申請CBC Latch,查詢資料塊在不在桶裡,這裡假設在記憶體裡。
-
修改資料塊。
-
釋放CBC Latch。
以上的描述看似是非常通暢,但是存在一個問題,由於CBC Latch的持有是排他的,在持有CBC Latch的情況下,去修改資料塊,那麼這個Latch的持有時間就會比較長,這個長是相對於Latch的獲取和釋放這種CPU原子操作的,因此在持有CBC Latch的情況下修改資料塊,對於讀寫頻繁的資料庫/塊(熱點塊),那麼勢必會造成CBC Latch的爭用,基於Latch的特性(自旋、休眠、再自旋),會造成大量CPU資源的浪費,導致資料庫的效能低下。
為了解決這個問題,Oracle設計了Buffer Pin的功能。也就是說,Buffer Pin這個機制存在的價值,是為了降低CBC Latch的爭用,節省CPU資源。
引入Buffer Pin後,修改資料塊的大致步驟如下:
-
首先依據資料塊地址計算出(Hash演算法)該塊所在的Hash Bucket。
-
然後申請CBC Latch,查詢、定位到資料塊
-
以X模式獲取資料塊的Buffer Pin。
-
釋放CBC Latch
-
在Pin的保護下,修改資料塊,完成後繼續以下步驟
-
獲得CBC Latch
-
釋放Buffer Pin
-
釋放CBC Latch
步驟複雜了許多,CBC Latch獲取/釋放共發生了兩次,工作量似乎整整大了兩倍。
可是極大程度降低了CBC latch的爭用。 因為持有CBC Latch的時間變得極短。 持有CBC Latch,只是為了在buffer header上增加buffer pin,目的變得單純和簡單。
你可能會說,Oracle這種解決方案就是按了葫蘆起了瓢,它只不過是轉移了競爭,以前是CBC Latch的爭用,現在是Buffer Pin的爭用。
這句話並沒錯。
但是Buffer Pin的爭用是不消耗CPU資源的。類似於佇列鎖的通知機制。而不會像Latch一樣去做自旋。
讀取資料塊增加S模式的Buffer Pin,修改資料塊增加X模式的Buffer Pin。S和S模式的Pin是相容的,可以併發的讀取,X和S模式是不相容的,後來的讀取會話需要產生等待。
文章的開頭,我們舉了2個程式操作同一記憶體塊的例子,這裡我們在有了一些知識之後,再做下總結和回顧。
-
寫讀,同一個時刻,如果一個程式以X模式持有了資料塊的Buffer Pin,另一個程式想以S模式持有,那麼就會出現爭用,因為道理很簡單,X模式的Buffer Pin和S模式的Buffer Pin不相容。
-
寫寫,同理,兩個同時欲修改同一個資料塊的程式,只有一個程式可以獲取X模式Buffer Pin,另一個會話產生Buffer Busy Waits等待。
我們平時經常說讀不阻塞寫,寫不阻塞讀,那是在物理的資料塊級別,在記憶體裡,在同一時刻對於同一個記憶體塊的寫讀/寫寫都是互相阻塞的。
這裡接著上面把場景補充完整,“讀讀”不會產生Buffer Busy Waits等待,因為Pin模式是相容的。“讀寫”不會產生Buffer Busy Waits等待,一個程式正在讀資料塊,此時另一個程式要去寫這個資料塊,寫程式很聰明,它會copy出一個current塊出來(之前的塊成為CR塊),然後在current塊上進行寫操作,透過這種方式避免了競爭,規避了Buffer Busy Waits的爭用。
因為前一個程式是在讀取,而不是修改。這個場景下的copy就是安全的。
另外一點,因為讀取資料庫塊需要在Buffer header上增加S模式的Buffer Pin,屬於記憶體的修改操作,因此即使是讀取操作,CBC Latch的持有也是排他的,但是這個增加Pin的時間極短,在壓力正常的資料庫環境中引起CBC Latch大量爭用的可能性不大。
當然如果是大量程式對同一記憶體塊頻繁讀取,就會引起CBC Latch的爭用。
一些細節
最後,有必要對一些細節再做些補充:
-
一旦程式Pin住了一個資料塊,不需要立即去UNPin(移除Pin)。ORACLE認為在本次呼叫後還有可能繼續去訪問這個資料塊,因此直到本次呼叫結束才會做UNPin操作。
-
Oracle在對唯一索引/undo塊/唯一索引的回表/索引root、branch塊的設計上,在訪問(讀取)的時候,獲取的是共享的CBC Latch,不需要去對Buffer加Pin,直接在持有共享CBC Latch的情況下讀取資料塊。這樣做的原因是這些型別的塊,發生修改的可能性比較小,因此Oracle單獨的採用這種機制。因此對於普通資料塊的讀取都是需要獲取2次CBC Latch,而對於這種特殊的資料塊,只獲取一次共享CBC Latch就可以了。
-
我們上面所說的情況都是在資料塊已經存在在記憶體裡的情況。如果資料塊不在記憶體,有可能會產生Read By Other Session爭用等待。
-
上面描述只符合10G後的版本。在10G前讀讀也會產生Buffer Busy Waits,10G後把這方面的Buffer Busy Waits歸到了Read By Other Session等待裡。
總結
本文講述了Buffer Busy Waits是如何產生的及其機制,但是並沒有講解如何對其進行調優。Buffer Busy Waits等待設計的本質是為了降低CBC Latch的爭用。以兩個程式操作記憶體塊為例,在“寫寫”、“寫讀”場景下會產生Buffer Busy Waits,在“讀讀”場景下不會產生Buffer Busy Waits等待,在“讀/寫”場景下,發生寫操作的伺服器程式會去Copy出一個current塊來繼續寫操作,而不會去等待Buffer Busy Waits。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/22034023/viewspace-2212828/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- update/select也可能產生buffer busy waits。AI
- Oracle Buffer Busy WaitsOracleAI
- 【等待事件】buffer busy waits事件AI
- Buffer Busy Waits深入分析AI
- buffer busy waits引起的會話突增AI會話
- oracle buffer busy waits等待的含義OracleAI
- Buffer busy waits/read by other sessionAISession
- buffer busy waits你誤解了嗎?AI
- Buffer Cache以及buffer busy waits/gc相關事件AIGC事件
- buffer busy waits 平均等待時間AI
- buffer cache實驗7-buffer busy waits-完成AI
- GC Buffer Busy Waits in RAC: Finding Hot BlocksGCAIBloC
- 【TUNE_ORACLE】等待事件之“buffer busy waits”Oracle事件AI
- Oracle Dba必須瞭解的buffer busy waits等待OracleAI
- [摘錄]Oracle Wait Interface之Buffer busy waits事件OracleAI事件
- 等待事件_buffer_busy_waits_and_read_by_other_session(1)事件AISession
- 等待事件_buffer_busy_waits_and_read_by_other_session(2)事件AISession
- 等待事件_buffer_busy_waits_and_read_by_other_session(3)事件AISession
- 等待事件_buffer_busy_waits_and_read_by_other_session(4)事件AISession
- buffer busy waits與rac cluster wait之間的聯絡AI
- 模擬產生CBC LATCH與buffer busy wait等待事件AI事件
- 效能調整一則:buffer busy waits導致主要issueAI
- [20161214]關於Buffer Busy Waits.txtAI
- [20150122]buffer busy waits特例.txtAI
- buffer busy waits, latch cache buffers chains, read by other session區別AISession
- gc buffer busyGC
- gc buffer busy的優化GC優化
- Oracle Free Buffer WaitsOracleAI
- buffer busy wait 解析AI
- Oracle優化案例-Bug 5552515引起的buffer busy waits和表物理讀(二十四)Oracle優化AI
- gc buffer busy的最佳化GC
- buffer busy wait 的深度剖析AI
- wait event:gc buffer busyAIGC
- Buffer Busy Wait小結AI
- zt_buffer busy waitAI
- GC BUFFER BUSY問題的診斷GC
- JavaScript是怎麼誕生的JavaScript
- 等待模擬-BUFFER BUSY WAITAI