您好,登錄后才能下訂單哦!
如果你的數據庫性能經常抖動,時快時慢,你會怎么入手,又會怎么一步步排查解決的?是先看等待事件?還是看AWR或ASH?接下來優化SQL?調整參數?甚至更換硬件?本次分享一個我在GCS處理的案例,希望大家讀后會有新的收獲。
問題來了
在一個寧靜的早晨,本來打算能夠看會兒書,做幾個實驗來打發時間,剛剛拿起書,電話就如期而至,讓本來寧靜的早晨變成了工作的開始。仔細想想,這就是運維人的常態吧,也就釋然了。簡單聊了幾句,對問題的基本情況了解一些,并且讓客戶搜集了相關的信息,開始了問題的分析。
幾個rebuild索引操作等待超過10個小時!!!
問題分析
背景介紹
數據庫版本:12.2.0.1 RAC
OS:Oracle Linux
問題:rebuild索引慢
“套路來了”
有幾件事要確認:
1.索引大不大?---確認時間過長是正常還是異常,如果索引很大那么我認為等待時間長是正常的。已經確認索引不大,只有幾個G
2.時間花在哪?---決定下一步的排查方向。
大概思路有了開始發招:
第一招: 確認問題:
看起來重建索引的操作是通過 sqlplus 連接發起的。
根據上面的信息可知,一共記錄了三條索引的rebuild。
第二招:時間花在哪了?
既然確認了會話的確是在進行索引重建的工作,接下來到 ASH 里面去看一下這個會話在等待什么東西。
根據上面的輸出,看起來重建索引的語句有很多次都是在等待“ gc cr multi block request ”。這說明這個重建索引的操作需要通過 undo 中保存的 cr 塊來構造數據的一致性的鏡像 , 而且要訪問多個cr塊才可以完成操作。具體原理可以去看中亦學院第一期公開課的視頻。沒看的抓緊下載哈。
下面是關于這個等待事件的詳細的解釋:
原理解釋
:
這個等待事件說明申請者實例需要向遠程實例(可能是多個)申請多個(具體的數據塊數量取決于參數db_file_mulitblock_read_count的設置) cr 塊。這個等待事件只有在所有申請的數據塊都被成功返回之后才會結束,也就是說,如果有其中的一個數據塊因為某種原因沒有被成功接受的話,就需要重新申請所有的數據塊。這也是為什么gc current/cr multi block request 經常和等待事件gc cr failure/ gc current retry 同時出現的原因。
關于更多cache fusion 相關的等待事件的解釋,請參考《Oracle RAC核心技術詳解》 第十二章中的內容。
現在我已經有答案了,很多人看到 gc current/cr multi block request會覺得已經無從下手,似乎已經山窮水盡了, 到這里基本信息都有了,結合上邊的原理大家自己思考幾秒鐘,如果是你下邊改怎么繼續排查問題?問題原因就在后面,什么時候往下翻,由你決定…
.........
.........
.........
.........
.........
.........
.........
原因:重建索引需要向另外的實例申請多個數據塊。申請效率低,網絡參數設置不合理。
頭腦風暴:三個初步要排查的方向。
1 :在遠程實例上有一個 blocker 進程一直持有了一些塊,導致了申請者無法拿到數據;
2 :申請的數據塊太多了,導致了私網的負載太大,產生了性能問題;
3 : RAC 的私網配置存在一些問題,導致了數據無法被快速的傳遞到遠程節點。
繼續發招
第三招:排查blocker。
下面是 AWR 中的信息
Top 10 Foreground Events by TotalWait Time
以上的信息說明 global cache 相關的 cr 多塊讀取產生的等待是最多的,一共產生了 3030 次等待,總共的等待時間是 1733.7 秒,平均每次的等待時間是 572.19ms 。所以看起來每次等待的時間不是很長,并不像是由于某一個 blocker 進程阻塞了其它進程導致的。如果真是這種情況,應該出現的情況是這個等待事件的 waits 值 比較低,但是 Total Wait Time (sec) 和 Avg Wait 很高 。本著一切以事實說話的原則,繼續排查。
查看等待事件的柱狀圖信息:
絕大多數的等待時間都小于 512us
還有一部分的等待 1 小于 32ms
最長的等待時間也不超過
2s
說明: 11g , 12c 的 AWR 報告中,會包含每一個等待事件產生的等待時間對應的柱狀圖信息,它把等待事件對應的等待時間根據時間的長短分成了若干組,這樣就可以區分出來某一個等待事件所導致的等待時間是如何分布的,對應了解等待時間的構成很有幫助。
上面的信息說明主要的等待時間分布都小于512us,而少部分的等待要低于2s,沒有超過2s的等待。所以,更加證實了這個問題不是由于某一個Blocker進程阻塞了其它進程造成的 。
看到這里,基本上就可以排除方向 1 了,繼續發招:
第四招:排查私網吞吐量
根據 AWR 中私網的流量信息( EstdInterconnect traffic (KB) )看起來當時私網的流量只有大概 1M/s 左右,并不是很高,在和正常情況下對比后,也沒有發現私網流量有大的變化。看到這里,方向 2 基本上也可以排除了。
那么,就只剩下方向 3 了。看看 OSW 的 netstat 輸出就能得到答案了。下面是部分截取出來的 OSW 的信息。
最后大招:一錘定音
netstat 輸出中的ip 層統計信息:
上面的信息說明節點 1 一直存在 IP 層的包重組失敗的問題。再回頭看了一下數據庫參數 db_file_multiblock_read_count 的配置,發現這個參數被設置為了 126 ,又看了一下 ifconfig 的輸出 :
看起來問題的原因就比較明顯了,上面的信息說明私網網卡的 mtu 值為不到 2k。
對于一個數據庫 block size 為 8k 而且 db_file_multiblock_read_count = 126 ( 這意味著每個數據庫的多塊讀,例如: gc cr multi block read 需要在 IP 層被切割成 8192*128/2044=513 ,也就是大概 500 多個數據塊 )的數據庫,多塊讀會被切割得很散,而 UDP 協議本身是 Unreliable 的協議,這不僅是 IP 包的發送并不是有順序的,同樣的應用程序層( 例如: oracle 的 lms 進程 )一旦發現這 500 多個包里面有一個是無效的,整個包就需要被重組。
另外,我們在
awr
中也發現了這個數據庫實例一直存在著“
gc cr block lost
”的等待,這本身也說明了私網的傳輸效率的確是存在一些問題的
。
10 Foreground Events by Total WaitTime
給出解決方案之前先解答一個疑問:很多人會問三個方向是怎么來的?且容我細細講來 :
+
+
第一:等待事件的含義是想要從遠程實例申請多個數據塊兒過來,而且還必須是所有申請的塊都拿到之后,才算完成。
第二:RAC的cachefusion 是通過UDP 作為數據傳輸協議的,而UDP本身又是一種不可靠的數據傳輸協議,也就是說數據的傳輸是沒有編號的(不像TCP協議),而且數據完整性是要通過應用程序自己來驗證的。
第三:UDP協議底層也是要把數據切割成一個個IP包來進行傳輸的
。
+
+
引用《 Oracle RAC 核心技術詳解》中的內容,一個數據包從一個實例到另外的一個實例是要經歷下面的步驟的:
步驟1:節點1的lms進程需要發送一個數據塊(假設db_block_size=8k,MTU=1500)給節點2的一個進程,并把這個請求通知OS(操作系統);
步驟2:節點1的操作系統需要將這個數據塊切成大概6個數據分片,放入節點1相應端口的UDP 發送緩存(SendBuffer);
步驟3:數據分片被陸續的通過網絡發送到了節點2;
步驟4:節點2 的操作系統收到了發送過來的數據包,保存到對應的UDP接收緩存(Recevie Buffer);
步驟5:節點2開始組裝數據分片,當所有的6個數據分片都被成功組裝之后,OS將組裝過的數據包發送給相應的接收進程;
步驟6:節點2的接收進程處理收到的數據包
。
用一個類比的例子:
我到銀行去存
100
萬(雖然我沒有這么多錢!),在銀行宣布存錢成功之前,它要完成以下的過程:
1
:把我的
100
萬,交給
10
個人,
10
臺點鈔機,確認我存的錢數是
100
萬;
2
:把這
100
萬放到銀行的保險柜里;
3
:通知我存錢成功。
在整個過程中,可能會出現的狀況是:
++
有一張
100
元紙幣卡在了點鈔機里面,怎么也拿不出來,那么這臺點鈔機就是一個
Blocker
,它阻塞了別人,讓點錢的過程不能完成。
++
每臺點鈔機都很慢,每分鐘只能點
10
張紙幣,整體拖慢了點鈔的時間。
++
把錢放到保險柜里面的工作人員每次只能運送
1
萬塊到保險柜里,也就是傳輸的時候太慢了。
既然知道了這中間發生的整個過程,又有了類比的過程,那么就很容易想到,中間可能出現的問題的可能性了。那么上面提到的三個方向也就自然而然的浮現到我的頭腦中了。
解決方案
既然知道了問題原因是由于 ip 層需要把每個多塊讀的 udp 包切成 500 多個小的 ip 包進行傳輸,導致了 IP 層進程出現碎片重組失敗,那么解決的方法也就有以下的幾種 。
+
+
方法
1
:把私網網卡的
MTU
值調整成至少
7000
,這樣就能夠讓
IP
層不需要把數據切得太碎,從而提高傳輸效率;
方法
2
:把數據庫參數
db_file_multiblock_read_count
調小,讓每次發送的數據包大小下降,讓
IP
層不需要把數據塊切得太碎,提高傳輸效率;
方法
3
:把
UDP
的碎片重組
buffer
調高,使
IP
層有更多的時間把碎片重組成完整的數據包,降低整個數據包重傳的概率。
+
+
最后,用戶選擇了把下面的參數調大
net.ipv4.ipfrag_high_thresh=16777216
net.ipv4.ipfrag_low_thresh= 15728640
并且把數據庫參數 db_file_multiblock_read_count 調整到 16, 在應用了改變之后,重建索引的操作大概 5 分鐘就完成。
總結
1.對于
RAC
數據庫,
cache fusion
的私網通信是通過
UDP
實現的,而對于多塊讀,需要所有請求的數據塊都到達遠程節點才算請求操作完成。哪怕,只有一個數據包沒有被傳輸過來,都需要所有數據塊兒進行重傳;
2.對于多塊讀的操作,每次請求的數據塊數量是通過參數 db_file_multiblock_read_count來控制的;
3.對于RAC系統,要特別注意UDP相關的操作系統內核參數的設置,不光要注意udp buffer大小的配置,還要注意碎片重組的buffer大小配置。
本文轉載于中亦安圖
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。