rac 遭遇GC BUFFER BUSY 處理思路

531968912發表於2017-05-03

一朋友求助說他的ORACLE RAC伺服器負載不是很穩定,時高時低,且沒有任何規律。摘取負載高峰時間的一段日誌來分析,最大的等待如下:

^LTop SQL Statements       DB/Inst: BOSSCENT/bosscent1  (May 19 13:17 to 13:32)
 
       SQL ID    Planhash % Activity Event                             % Event
------------- ----------- ---------- ------------------------------ ----------
f9rf7a8cg40nt         N/A       9.14 gc buffer busy                       2.53
insert into test(id,user_id,point_num,time,point_gettype,sex) values(
:1,:2,:3,sysdate,:4,:5)
 
                      N/A       9.14 gc current block busy                2.22
insert into test(id,user_id,point_num,time,point_gettype,sex) values(
:1,:2,:3,sysdate,:4,:5)
 
                      N/A       9.14 gc current block 2-way               1.42
insert into test(id,user_id,point_num,time,point_gettype,sex) values(
:1,:2,:3,sysdate,:4,:5)
bs6z6hs8sum53  1007834728       8.09 gc buffer busy                       2.16
update test set id=:1 where id=:2

明顯看到出現大量gc buffer busy等待,與單例項不同,在RAC環境中,由於多節點的原因,會因為節點間的資源爭用產生GC類的等待,而這其中,GC Buffer Busy Waits又是最為常見的,我們看下ORACLE官方對這個等待事件的解釋:

gc buffer busy:
This wait event,also known as global cache buffer busy prior to Oracle 10g,specifies the time the remote instance locally spends accessing the requested data block. This wait event is very similar to the buffer busy waits wait event in a single-instance database 。

那麼如何解決gc buffer busy帶來的效能問題?一般有兩種方法:


一、分割應用
就是指把出現gc buffer busy等待的SQL,單獨配置一個資料來源,在執行的時候指定到叢集中的某一個例項。在執行產生gc buffer busy的SQL的時候,使用這個資料來源。

這樣的缺點是,如果指向一個單例項,這些操作負載太高的話,一個例項可能會抗不住。

二、修改表底層結構

在問題表上加入一個欄位inst_id,也就是例項編號,這個欄位作為主分割槽欄位,按照這個分割槽做範圍分割槽。並且每次插入的時候給這個欄位賦一個常量,也就是例項編號。

這樣的缺點是,需要修改表結構,風險很大,而且如果以後擴充套件節點的話,還需要重新改表結構。

兩種方法各有長短,需要根據實際情況選擇,不過我個人還是傾向於第一種方法。

本文轉自:


inst_id
分割槽避免rac gc buffer busy




透過ASH報告,我看到剛才系統HANG住的時候,主要的等待事件是buffer busy wait


Avg Active


Event Event Class % Activity Sessions


----------------------------------- --------------- ---------- ----------


buffer busy waits Concurrency 72.55 9.31


enq: HW - contention Configuration 14.21 1.82


gc buffer busy Cluster 7.67 0.98


CPU + Wait for CPU CPU 2.13 0.27


-------------------------------------------------------------


看樣子是由於熱塊衝突導致系統HANG住的,而且高水位推進相關的鎖等待也很嚴重,應該系統中有大量的資料插入。從這個情況看想簡單的透過調整引數來解決問題是不大可能,必須從應用的特點去分析,才有可能找到解決方案。於是我問郝經理:"你的應用是什麼樣的,是不是有大量的插入操作?"


郝經理告訴我這個系統是企業應用整合系統,是從其他系統中接收資料,經過處理後儲存在本系統中,供經營分析系統使用。目前的壓力測試中的主要操作是對34張大表進行大批次的資料插入,其中還有張表裡帶LOB欄位。


我和郝經理研究了一下,對這些資料的訪問,除了大規模的資料插入外,一般來說是按主鍵訪問,或者按某些分類條件的小範圍查詢,每次範圍查詢頂多佔整個表資料量的幾萬分之一,並且範圍查詢的比例相對較小,僅佔整個系統查詢數量的10%不到。這種情況是典型的可以使用HASH分割槽的,透過HASH分割槽既可以解決BUFFER BUSY WAIT的問題,又可以解決enq: HW -contention的問題。於是我建議郝經理把這幾張表按照主鍵MSG_IDhash分割槽,先嚐試一下16個分割槽,看看能不能解決問題。


按照我的建議做了HASH分割槽後,壓力測試重新開始了,這回看樣子效果很不錯,從em控制檯上看,buffer busy wait等待已經少了很多,而且enq: HW - contention等待也消失了。



Avg Active


Event Event Class % Activity Sessions


----------------------------------- --------------- ---------- ----------


gc buffer busy Cluster 90.69 14.83


gc current request Cluster 6.05 0.99


CPU + Wait for CPU CPU 1.05 0.17


目前的主要等待是gc buffer busy,由於目前在連個節點上各有40個併發插入的會話在進行資料插入,因此全域性BUFFER等待的問題肯定是存在的,目前壓力測試已經進行了1個多小時了,從em觀察到的情況來說系統一直還很平穩。現在的時間已經是中午的12點半了,郝經理建議我們先去吃飯,等吃完飯回來再看看結果。


在下面的食堂裡簡單吃了點東西,我們就回到了辦公室,現在是下午的1320分了,壓力測試也已經開始了差不多2個小時了,系統的狀態依然和我們吃飯前一樣,還沒有出現hang住的現象。不過從平均事務響應時間來看,現在比一個小時前要慢了40%,這是一個十分不好的現象,如果這種趨勢延續下去的話,很可能會再次出現系統HANG住的現象。


看著郝經理他們興奮的樣子,我給他們潑了盆冷水,可能問題還是沒徹底解決,從目前的趨勢上看,有可能系統還會HANG住。我正在和他解釋為什麼我會有這種預感,突然從EM上看到系統活躍情況突然下降了,系統可能又HANG住了。


我連忙做了一個3級的hanganalyze,從trace上看:


Open chains found:


Chain 1 : :


<0/786/9/0xff010e58/9474/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>


Chain 2 : :


<0/791/32/0xff00e6a8/9404/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>


Chain 3 : :


<0/792/12/0xff00ee98/9408/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>


Chain 4 : :


<0/794/19/0xff00d6c8/9334/gc buffer busy>


-- <0/785/26/0xff011e38/9512/gc current request>



大量的gc buffer busy導致了大量的gc current request等待。很多會話由於gc buffer busyHANG住一段時間,實際上系統並沒有真正的HANG住,而是變得十分慢而已。不過如果這種情況的範圍如果擴大的話,就會導致應用軟體出現問題,產生丟失資料的現象。過了幾分鐘,郝經理那邊也確認了這次系統HANG住,1號節點的應用被掛起了35秒鐘,丟失了70多條資料,實驗再次失敗了。


看樣子GC BUFFER BUSY最終還是導致了嚴重的問題。由於他們的應用沒有針對RAC進行最佳化,同一個應用分別在2個節點上跑,所以導致了嚴重的節點間的熱塊衝突。也許把這個應用集中在一個節點上就能夠解決問題。我把我的想法和郝經理說了,郝經理覺得可以試試,不過他們的系統發展起來特別快,所以從最初做設計的時候就考慮要使用RAC,而且今後不僅要支援雙節點,還可能擴充套件為3節點甚至4節點。目前的業務有可能單節點能夠支援,不過今後一個節點可能無法支撐所有的負載。


我考慮了一下,剛才應用放在兩個節點上跑的時候,兩個伺服器的CPU使用率都已經超過60%了,如果跑在一個節點上,確實負載挺大的,一個節點還真有可能支援不了,更不要說今後系統擴充套件性的問題了。看樣子必須從底層結構上進行調整了。我問郝經理,如果在表裡面加一個欄位,並且每次插入的時候給這個欄位賦一個常量,這樣修改程式他們的工作量大不大。郝經理想了想說應該問題不大,修改一下也就是10分鐘的事情。


我說如果這樣就好辦,我們可以對錶結構做一個調整,來徹底解決這個問題。我們重新對錶進行分割槽,使之成為一個複合分割槽表,在這張表上加入一個欄位inst_id,也就是例項編號,這個欄位作為主分割槽欄位,按照這個分割槽做範圍分割槽後,再設定msg_idhash分割槽。調整後的表結構如下:


CREATE TABLE QSTORE


(


MSG_ID VARCHAR2(64 BYTE) NOT NULL,


DOCE_ID VARCHAR2(100 BYTE) NOT NULL,


DOC_KEY VARCHAR2(100 BYTE) NOT NULL,


BUS_NAME VARCHAR2(100 BYTE),


MODULE_NAME VARCHAR2(100 BYTE),


CATEGORY VARCHAR2(64 BYTE),


SUB_CATEGORY VARCHAR2(64 BYTE),


DOC_SIZE NUMBER(11) DEFAULT 0,


CREATE_TIME DATE,


MODIFY_TIME DATE,


EXPIRED_TIME DATE,


DOC_FLAG NUMBER(2),


Inst_id number


) initrans 20 pctfree 20 tablespace TS_DATA_EAI


PARTITION BY RANGE(inst_id)


SUBPARTITION BY HASH(msg_id) SUBPARTITIONS 8


(PARTITION p1 VALUES LESS THAN (2),


PARTITION p2 VALUES LESS THAN (3));;


Inst_id的值就是插入程式連線到的例項的ID,這樣調整後,在1號節點上插入的資料將全部被插入到inst_id=1的分割槽,插入操作就不會產生大量的global cache request了。這種做法也是在RAC上解決GC BUFFER BUSY的常用方法之一。


郝經理很快就明白了我的意思,上樓去安排開發人員修改應用了。我也趁機休息休息,準備下面的測試了。這時候老儲的電話又打了進來,那個問題終於解決了,透過hcheck對資料字典進行檢查,發現有一張表的資料字典出現了不一致,在tab$中還有記錄,但是在obj$裡的記錄缺失了,查詢這個表空間中有什麼物件找不到,但是刪除tablespace的時候又刪除不了。把tab$中的資料手工刪除後,表空間就成功的刪除了。


剛和老儲通完電話,郝經理的電話就打了進來,他說應用已經修改好了,他已經開始了測試,大概10分鐘後壓力就會載入到資料庫上,讓我監控一下有沒有什麼問題。從測試剛開市的情況看,gc buffer busy基本上消失了,系統也比較平穩,從EM的監控情況來看,系統一切都很平穩,系統已經執行了一個多小時,從awr報告來看,現在的平均事務響應時間,和系統剛剛啟動時差別不大,並且gc buffer busy 等待事件也已經不在top 5等待時間裡了。看樣子透過這麼最佳化,系統趨於穩定了。郝經理建議我們先回去,壓力測試做一晚上,明天上午10點再來看結果。如果那時候發現系統一切正常,那麼說明問題已經解決了。


select t.INSTANCE_NUMBER into p_inst_id from v$instance t


透過procedure進行插入,在執行的開始,取得instance_id


本文轉自:http://yu85910.blog.china.com/200903/4504368.html


gc buffer busy: 產生這個等待事件是由於例項間產生熱塊爭用造成的,要解決這個問題有兩種方法:


第一、分割應用:把應用集中在一個節點上執行


第二、對錶新增一個欄位,這個欄位存放例項的id號,如果在節點1執行的那麼存放節點1的例項id號, 如果在節點2執行的那麼存放節點2的例項id,在執行之前首現獲取例項的id號。


[@more@]

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/25462274/viewspace-2138366/,如需轉載,請註明出處,否則將追究法律責任。

相關文章