Oracle 10g RAC中的DRM

wei-xh發表於2011-07-26

http://blog.china.com/u/071030/89253/201007/6618907.html

 

在RAC環境中,Oracle使用GRD(Global Resource Service)來記錄各個RAC節點的資源資訊,具體透過GCS(Global Cache Service)和GES(Global Enqueue Service)這兩個服務進行管理。
      由於在RAC中每個節點都有自己的SGA和buffer cache,為了保證Cache資源的一致性和提高效能,GCS和GES會指定RAC中的一個instance來管理Cache,這個節點這時就是Resource Master。
      在10g以前,Cache資源是不能在各個節點間移動的,除非重啟或者某節點因為其他異常被RAC驅逐等情況。而10g的DRM就解決了這個問題,它可以保證cache能夠被remaster到頻繁訪問這部分資料的節點上,從而提高RAC的效能。DRM的全稱是Dynamic Resource Mastering,metalink上的Doc ID:  390483.1文件詳細介紹了DRM的資訊。 

      從理論上講,利用此項技術,非master節點對所需資源有頻繁訪問需求時,可以提升為master節點,從而減少大量後續的跨節點資源訪問需求。
      但是,首先從根本上說,一個好的RAC應用設計,本就應該極盡所能的取避免同一資源的多節點訪問,如果不存在同一資源的多節點訪問,則DRM所要解決的問題,就根本不存在。其次,DRM本身是需要消耗資源的,並且存在諸多bug,對於一個設計較差的系統而言,頻繁的DRM,也會引發Libary cache lock而導致例項掛住。
      更嚴重的,在10.2.0.3系統上,曾經遇到一個case,電信行業的巨型資料庫,rac的2號節點由於批次處理作業在非業務時間段,首先cache了一張40G的表,而到了業務時間段後,rac的1號節點的OLTP業務需要頻繁訪問該表,此時,故障發生了,由於DRM的介入,2號節點開始將記憶體內的40Gcache資料向1號節點傳輸,心跳網段千兆頻寬被耗盡,RAC陷入僵死階段,足足維持了40分鐘。
      事後檢查網路流量圖,該時段內,私有網路流量持續保持在90M/s的峰值水平。
      根據metalink確認,該問題確實由DRM機制引起,最終解決方案,使用隱含引數,將DRM特性遮蔽:
_gc_affinity_time=0  
_gc_undo_affinity=FALSE 

      因此,從根本上來說,drm的出現,只是在理論上的一種緩解,而並不能在實際的大型應用中發揮其作用。就類似於Oracle自己針對RAC推出的自動負載平衡一樣,只是一種看起來很美的東西,如果真的有人用了,呵呵,那就只能等死吧。或許壓力極小的資料庫無所謂,但我沒遇到過,話又說回來,壓力極小,又何必上RAC呢。
ORACLE中所有的資料都是以塊的方式儲存的,那麼在RAC環境下,一個塊就會存在被多個節點讀寫的情況。這個時候如果有一個節點需要對這個塊進行讀寫,那麼首先可能就需要知道這個塊的資訊,比如這個塊是否在記憶體中、是否是髒塊、是否需要構造一致性讀、塊上是否有其他人對其中某行進行了鎖定等等,那麼這些塊的資訊就需要而且只能由一個節點來進行管理,其他節點需要知道這個塊的資訊的時候,就去查詢GRD(Global Resource Directory),GRD告知你誰是這個塊的MASTER,然後你就可以去MASTER那裡請求對資源的訪問。假如這個資源是MASTER在節點1,而節點2需要頻繁的訪問這個塊,那麼就需要非常多的請求MASTER的過程,這個過程要透過心跳網路來完成,速度比直接訪問記憶體慢N多倍,所以效率就會有問題。那麼ORACLE就會把這個塊的MASTER許可權從節點1交給節點2來提高效率。DRM是10G才出現的功能,並且在10.1和10.2中實現的精度是不一樣的。10.1是以FILE為單位的,10.2是以SEGMENT為單位的。


跟BUFFER CACHE的訪問機制類似,ORACLE會使用HASH的方式來決定每個BLOCK的MASTER是哪個節點,預設情況下HASH的BUCKET是128,也就是說ORACLE按照連續128個BLOCK在一個節點,然後接下來的128個BLOCK在另外一個節點這樣的機制來進行平均分配塊的MASTER。這個BUCKET可以透過隱含引數_lm_contiguous_res_count來進行修改。

每個BLOCK是被哪個節點MASTER的,可以透過X$KJBR.KJBRNAME來檢視,這個欄位的記錄不那麼直觀,那麼可以透過下面兩個函式來進行轉換,得到MASTER的是哪個檔案的哪個塊。
CREATE OR REPLACE FUNCTION GET_FILE_NUMBER(P_RESOURCE_NAME VARCHAR2)
RETURN INTEGER IS
POS1 INTEGER := INSTR(P_RESOURCE_NAME, 'x', 1, 2);
POS2 INTEGER := INSTR(P_RESOURCE_NAME, ']', 1, 2);
S VARCHAR2(30) := SUBSTR(P_RESOURCE_NAME, POS1 + 1, POS2 - POS1 - 1);
BEGIN
RETURN TO_NUMBER(S, 'XXXXXXXX') / 65536;
END;
/
CREATE OR REPLACE FUNCTION GET_BLOCK_NUMBER(P_RESOURCE_NAME VARCHAR2)
RETURN INTEGER IS
POS1 INTEGER := INSTR(P_RESOURCE_NAME, 'x', 1, 1);
POS2 INTEGER := INSTR(P_RESOURCE_NAME, ']', 1, 1);
S VARCHAR2(30) := SUBSTR(P_RESOURCE_NAME, POS1 + 1, POS2 - POS1 - 1);
BEGIN
RETURN TO_NUMBER(S, 'XXXXXXXX');
END;
/

然後使用
SELECT GET_FILE_NUMBER(KJBRNAME), GET_BLOCK_NUMBER(KJBRNAME) FROM X$KJBR;
到每個節點查詢,從返回結果就可以知道這個節點MASTER了哪些BLOCK。

如果想手工的把一個SEGMENT的所有塊都MASTER到一個節點,首先要知道這個SEGMENT所對應的OBJECT的DATA_OBJECT_ID,然後使用:
oradebug lkdebug -m pkey DATA_OBJECT_ID

如果想使得所有塊的MASTER回到初始的根據HASH分配的狀態,那麼使用:
oradebug lkdebug -m dpkey DATA_OBJECT_ID

GV$GCSPFMASTER_INFO檢視記錄了REMASTER的結果,其中FILE_ID表示是哪個檔案,OBJECT_ID表示是哪個物件,CURRENT_MASTER表示當前的MASTER,PREVIOUS_MASTER表示之前這個資源是MASTER在哪個節點上的,REMASTER_CNT表示REMASTER的次數(不過這個數字好像不那麼靠譜)。其中如果PREVIOUS_MASTER為32767,表示這個資源一上來就MASTER在這個節點上的,沒經過REMASTER的。

另外三個檢視也記錄了REMASTER的相關資訊:
X$KJDRMREQ:Dynamic Remastering Requests
X$KJDRMAFNSTATS:File Remastering Statistics
X$KJDRMHVSTATS:Hash Value Statistics

LMD程式負責完成DRM的過程,所以DRM的TRACE會寫在LMD程式的TRACE檔案中。

DRM提高效率的同時也帶來一堆問題,在整個10.2.0.2版本之前,DRM都不那麼穩定,ORACLE也不推薦使用(但這又是預設在使用的功能)嚴重的會導致系統HANG住。可以透過下面兩個隱含引數來禁止DRM的發生:
_gc_undo_affinity=FALSE
_gc_affinity_time=0

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

相關文章