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