91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Buffer Busy Waits是怎么產生的?

發布時間:2020-08-10 23:21:27 來源:ITPUB博客 閱讀:149 作者:wei-xh 欄目:關系型數據庫

哪些場景會產生Buffer Busy Waits

Buffer Busy Waits是Oracle 數據庫常見的一個等待,特別是在并發寫比較頻繁的環境里。作為一個Oracle DBA,如果你從未遇到過Buffer Busy Waits等待,那么你算不上一個真正的Oracle DBA。

產生這個等待的原因是,在內存級別,在同一時刻對同一內存塊進行讀寫產生了爭用。這里我以2個進程對數據塊的操作為例,歸納出產生Buffer Busy Waits的場景:

  1. 寫寫,例如一個進程正在對內存塊做更改,此時另一個進程也要修改這個內存塊

  2. 寫讀,例如一個進程正在對內存塊做更改,另一個進程此時想要讀這個內存塊。你可能會問,oracle為什么不去copy正在修改的塊構造CR塊,然后去讀構造出的CR塊,理由很簡單,內存塊正在寫(變化)的過程中去做copy,是一個不安全的動作。

按照字符的排列組合,還剩”讀讀“、”讀寫“兩個場景,這兩個場景都不會導致產生Buffer Busy Waits(這里很重要的一個假設是2個進程),理由我們后面再給出,這里按住不表。

為什么要設計這個等待

Oracle為什么要設計這個等待,這是個好問題,本篇文章也主要是為了解答這個疑問。

“為什么”要比“是這樣做的”的更重要,前者講的是邏輯和洞見,后者描述的是過程和結果。

回答這個問題之前,首先設計一個場景,“假如沒有這個等待,讀寫數據塊是如何進行的”,當然這個場景是設計出來的,其實并不存在。

那我們開始,假設場景是這樣子的,我們要對一個數據塊做寫入操作,遵循如下步驟:

  1. 首先依據數據塊地址計算出(Hash算法)該塊所在的Hash Bucket。

  2. 根據桶的編號,計算出保護這個桶的CBC Latch,然后申請CBC Latch,查找數據塊在不在桶里,這里假設在內存里。

  3. 修改數據塊。

  4. 釋放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后,修改數據塊的大致步驟如下:

  1. 首先依據數據塊地址計算出(Hash算法)該塊所在的Hash Bucket。

  2. 然后申請CBC Latch,查找、定位到數據塊

  3. 以X模式獲取數據塊的Buffer Pin。

  4. 釋放CBC Latch

  5. 在Pin的保護下,修改數據塊,完成后繼續以下步驟

  6. 獲得CBC Latch

  7. 釋放Buffer Pin

  8. 釋放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。


向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

饶河县| 肇东市| 葫芦岛市| 宁强县| 新宾| 尼玛县| 郁南县| 榆树市| 施秉县| 乌兰浩特市| 马关县| 东乌珠穆沁旗| 通渭县| 乌拉特中旗| 巫山县| 调兵山市| 大丰市| 娄底市| 会理县| 南宁市| 甘孜县| 安陆市| 泸州市| 铜鼓县| 临海市| 凤城市| 闸北区| 长宁区| 泽普县| 遂宁市| 青浦区| 绥阳县| 华安县| 元阳县| 平湖市| 罗平县| 义马市| 广灵县| 蓬安县| 中西区| 常山县|