RAC 동작 원리

GRD & cache fusion : 한 인스턴스가 변경하려는 블록이 다른 인스턴스에 의해 동시에 변경되지 않도록 보장 하고 인스턴스 수가 증가 할수록 이러한 문제가 더 복잡해지지 않도록 함

GRD (Global Resource Directory) - 자원 접근 제어

  • GES (Global Enqueue Service) : 인스턴스 상호간 락관리, LCK0, LMD, LMON
  • GCS (Global Cache Service) : 클러스터 내 블록 관리 : LMSn
    • GCS, 캐시 퓨전 시 대부분 LMSn, LMD 를 통해 다른 인스턴스의 SGA 접근
  • 리소스의 락킹(큐잉) 및 모든 인스턴스에서 리소스를 명확히 확인 할 수 있는 메커니즘 필요
    • v$dlm_ress (distributed lock manager resources) : v$resource 와 유사 (락을 설정할 수 있는 대상)
    • v$ges_enqueue (the global enqueues services enqueues, v$dlm_locks) : v$lock 와 유사 (락을 수행한 대상)
    • GRD (global resource directory)
      • 딕셔너리 캐시내의 모든 항목, 메모리 내에 존재하는 모든 블록과 같은 매우 많은 오브젝트를 관리 해야 함
      • 다수의 인스턴스가 지속적으로 락킹관련 정보를 복사 해야 함 (동일한 GRD 를 모든 인스턴스에 복사하지 않기 때문에 인스턴스가 증가 해도 락과 관련된 트래픽이 기하급수적으로 증가하지 않는다)

RAC 초기 버전(OPS)은 일반적으로 하나의 락이 넓은 범위를 관리.
RAC 최신 버전은 하나의 락 = 하나의 블록이 기본 접근 방식 (fine-grained locking), READ-ONLY TABLESPACE 같은 특별한 경우에는 넓은 범위(파일)를 관리하기 위해 하나의 락이 사용됨

GES/GCS 리소스 확인


SQL> select resource_name, current_utilization, max_utilization
  from v$resource_limit
 where resource_name like '%g_s%'
 order by resource_name;

RESOURCE_NAME     CURRENT_UTILIZATION MAX_UTILIZATION
----------------- ------------------- ---------------
gcs_resources                    6615            6615
gcs_shadow                       9716            9716
ges_cache_ress                   1218            1364
ges_locks                        4911            5071
ges_ress                         7772            7872

SQL> select *
  from v$sgastat
 where name like '%gcs%'
    or name like '%ges%'
 order by name;

POOL         NAME                                 BYTES
------------ -------------------------- ---------------
shared pool  gcs resource                       4927120
shared pool  gcs shadows                        3630512
shared pool  ges resource                       2602392
shared pool  ges enqueues                       5171824

-- v$resource_limit 는 ges_locks 를, v$sgastat 는 ges enqueues 를 보여줌, GCS 에 대한 enqueue(lock) 정보는 없음
-- 캐시 처리 빈도수가 훨씬 많고, 전송되는 패킷의 크기도 훨씬 크기 때문에, 캐시 처리와 일반적인 enqueue 처리를 분리 함 : global cache resources 를 위한 분리 구조 (gcs RESOURCE, gcs SHADOWS)
-- 오라클은 리소스를 제어(mastering)하기 위한 권한을 모든 인스턴스에게 동등하게 공유 하나, master 를 제외한 인스턴스는 master 리소스로 부터 중요한 정보의 일부를 포함하는 shadow 리소스를 유지.

Master 및 Shadow

리소스 마스터링

리소스 식별자에 해시 함수를 적용하여 임의로 분배 (예: XYZ 테이블에 락을 설정하려면, 테이블의 OBJ_ID 를 이용하여 몇가지 연산을 수행한 후, 해당 테이블의 마스터 TM 리소스를 소유한 노드 확인 후, 락 설정 시도)

리소스 조회 데모


-- WRH$_LATCH (OBJ_ID:6334,0x18be) 의 TM 리소스 조회
select *
  from gv$dlm_ress
 where resource_name like '%0x18be%TM%';

select *
  from gv$ges_enqueue
 where resource_name1 like '%0x18be%TM%';

-- 세 개의 모든 노드에서 관련된 이름의 리소스가 존재, enqueue 의 할당(gv$ges_enqueue)는 노드 1에서만 보여짐
-- INST_ID = 1 : TM 리소스의 마스터 노드, 두개의 인스턴스(OWNER_NODE IN (1, 2))가 리소스를 사용 (OWER_NODE 는 0 부터 시작)
-- GRANT_LEVEL, REQUEST_LEVEL : KJUSERCW(concurrent write), v$lock 에서 보여지는 row-exclusive 와 같음
INST_ID				: 1
HANDLE				: 000000008D2537C0
GRANT_LEVEL			: KJUSERCW
REQUEST_LEVEL			: KJUSERCW
RESOURCE_NAME1			: [0x18be][0x0],[TM][ext 0x0,0x0
RESOURCE_NAME2			: 6334,0,TM
STATE				: GRANTED
OWNER_NODE			: 2
--------------
INST_ID				: 1
HANDLE				: 000000008D256E60
GRANT_LEVEL			: KJUSERCW
REQUEST_LEVEL			: KJUSERCW
RESOURCE_NAME1			: [0x18be][0x0],[TM][ext 0x0,0x0
RESOURCE_NAME2			: 6334,0,TM
STATE				: GRANTED
OWNER_NODE			: 1
--------------

-- 리소스 유형이 다르면 약간은 다르게 동작할 수 있음 (특히 버퍼캐시, 아래 예는 히스토그램과 관련된 딕셔너리 캐시 유형)
-- GRANT_LEVEL : KJUSERPR (protected read, v$lock 의 모드 4), INST_ID = 2 가 이 리소스의 마스터, INST_ID IN (1, 3) 은 SHADOW
SELECT INST_ID, OWNER_NODE, GRANT_LEVEL, RESOURCE_NAME1
  FROM GV$GES_ENQUEUE
 WHERE RESOURCE_NAME1 LIKE '%[0xf13e8525][0xa660035f],[QQ]%'
 ORDER BY INST_ID, OWNER_NODE;

  INST_ID OWNER_NODE GRANT_LEV RESOURCE_NAME1
--------- ---------- --------- -------------------------
        1          0 KJUSERPR  [0xf13e8525][0xa660035f],[QQ][
        2          0 KJUSERPR  [0xf13e8525][0xa660035f],[QQ][
                   1 KJUSERPR  [0xf13e8525][0xa660035f],[QQ][
                   2 KJUSERPR  [0xf13e8525][0xa660035f],[QQ][
        3          2 KJUSERPR  [0xf13e8525][0xa660035f],[QQ][


3노드 클러스터에 대한 master 와 shadow 의 관계

REMASTERING

  • 마스터 리소스 찾는 방법은 버전에 따라 다르고, 데이터 블록에 대해서는 특별한 경우도 있음
  • DATA OBJECT 가 특정 인스턴스에서 많이 사용된다는 것을 감지하면, 그 인스턴스를 DATA OBJECT의 모든 블록에 대한 리소스 마스터로 지정
    • 버전에 따라 <전혀 동작하지 않음> => <파일 레벨 동작> => <오브젝트(SEGMENT) 레벨 동작>
  • 오브젝트 수는 블록 수와 비교하면 상대적으로 작으므로, 리소스 마스터 정보를 포함한 DATA OBJECT 맵(map) 유지 가능 (산술 연산 수행 전 맵 확인)
  • 동적으로 오브젝트를 리마스터 할때, 아주 짧은 순간 GRD가 동결 됨 (몇 초)
  • STATSPACK, AWR 을 통해서 리마스터링 횟수 및 오브젝트 리마스터에 대한 통계 제공

GCS 와 GES

  • 오라클이 다루어야 하는 리소스의 개수

리소스 유형 별 정보


-- 3 노드 클러스터의 한 노드에서 인스턴스가 기동된 후 몇 분 후에 수행
SQL> select -- resource
       substr(resource_name, instr(resource_name, ',')+2, 2), count(*)
  from v$dlm_ress
 group by substr(resource_name, instr(resource_name, ',')+2, 2)
 order by count(*);

SUBSTR(R COUNT(*)
-------- --------
...
TM            558
QC           1061	-- dictionary cache, segments
BL           2802
QQ           3899	-- dictionary cache, histograms
QI           3959	-- dictionary cache, objects

SQL> select -- enqueues
       substr(resource_name2, -2), grant_level, request_level, count(*)
  from v$ges_enqueue
 group by substr(resource_name2, -2), grant_level, request_level
 order by count(*);

 SUBSTR(R GRANT_LEV REQUEST_L   COUNT(*)
 -------- --------- --------- ----------
 ...
 QC       KJUSERPR  KJUSERPR       1060
 BL       KJUSEREX  KJUSERNL       2552
 BL       KJUSERPR  KJUSERNL       3891
 QI       KJUSERPR  KJUSERPR       4888
 QQ       KJUSERPR  KJUSERPR       6140

-- 다수의 파티션을 가진 파티션 테이블이 존재하고 히스토그램이 많은 경우 딕셔너리 캐시를 의미하는 Qx 리소스가 많아짐
-- 블록을 관리하는 BL 유형이 Qx 유형 보다 적으나 데이터베이스가 운영 되면서 증가 하게 됨

-- BL 리소스는 하나의 블록을 관리 (예외: GLOBAL TEMPORARY TABLE, READ-ONLY TABLESPACE)
-- 블록이 인스턴스 중 하나의 버퍼캐시에 적재되면 관련된 BL 리소스가 존재 하게 됨
-- 이론상 마스터 BL 리소스 수 = 전 시스템의 버퍼 수, 실제로 마스터 BL 리소스 수 < 전 시스템의 버퍼 수 (하나의 블록에 대한 여러 개의 복사본을 가지고 있으므로)

RAC 에서 블록을 보호하기 위해 BL 리소스 유형을 사용 함

  • 버퍼를 보호하지 않음
  • BL 리소스의 ID1/ID2 값으로 블록 주소 식별
  • Qx(딕셔너리 캐시)는 매우 안정적임 (데이터베이스 기동 후 몇 분내 딕셔너리 캐시에 대부분 정보가 적재 되며, 아주 천천히 변경됨)
  • BL(버퍼 캐시)는 급격히 변경될 수 있음 (블록들이 버퍼 캐시로 적재되고, 밀려나가고, 버퍼 캐시에 적재된 블록과 리소스의 리스트를 일치시키는 작업 및 BL 리소스에 대한 EXCLUSIVE 락을 소유하고 있는 한 노드만이 블록을 변경할 수 있도록 지속적으로 락 모드 변경 작업 필요)
  • BL 리소스는 실제로 한 인스턴스에서 다른 인스턴스로 이동해야 함 (BL 락이 필요 함 = 해당 락이 관리하는 블록이 필요 함)
  • GES 는 블록에 대한 권한을 다룸, GCS 는 실제 블록을 다룸

캐시퓨전 - 클러스터 내 블록 이동

  • 보통 RAC 클러스터에서 발생하는 메시지의 대부분은 블록에 대한 것 (GES : 블록 권한 다룸, GCS : 블록 복사본 전송)
  • RAC 인스턴스가 블록을 버퍼에 적재할 때 마다, BL 리소스를 생성하는 트리거가 수행 됨
    • 디스크로 부터 블록을 읽기 전에, 리소스가 위치할 곳을 계산하고 블록이 이미 캐시에 적재되었는지 확인하기 위해 리소스 마스터 인스턴스에서 정보를 얻음 (이 경우 인터커넥터를 통해 블록을 전송 요청)
      CASE1)
      1. 블록 주소를 통해 마스터 리소스 위치 계산
      2. 리소스에 대한 enqueue 를 생성하기 위해 마스터 인스턴스에게 메시지 보냄
      3. 리소스가 없다면 마스터 인스턴스는 리소스를 생성하고, 해당 리소스에 enqueue 를 등록하고 reader 에게 알림
      4. reader 는 shadow 리소스 및 enqueue 를 생성하고 블록을 버퍼에 읽어 들임
      CASE2)
      1. 블록 주소를 통해 마스터 리소스 위치 계산
      2. 리소스에 대한 enqueue 를 생성하기 위해 마스터 인스턴스에게 메시지 보냄
      3. 마스터는 리소스의 존재여부 및 위치확인, 리소스에 등록된 current enqueue는 어느 인스턴스가 블록을 제공하기 적합한지 알려줌, 마스터는 리소스에 enqueue를 추가하고, 필요에 따라 리소스에 등록된 다른 enqueue를 변경한다 (다른 인스턴스에 메시지를 전송 한다), 그리고 선택된 인스턴스에게 블록을 전달하라고 지시 함
      4. 블록을 전송 받으면, reader 는 전송이 완료되었다는 것을 마스터 인스턴스에 알리기 위해 메시지를 전송한다. 그리고 shadow 리소스와 enqueue 를 생성한다.

4노드 클러스터 내의 3-way 블록 전송 / 처리순서

4노드 클러스터 내의 3-way 블록 전송 / 처리결과

  • 클러스터 내에서 블록 전송에 관련될 수 있는 노드의 수는 최악의 경우에 세 개이기 때문에 클러스터를 구성하는 노드의 개수는 비교적 큰 문제가 되지 않는다.
    • 블록을 원하는 노드
    • 해당 리소스에 대한 마스터 노드
    • 현재 해당 블록의 "BEST" 복사본을 가지고 있는 노드
  • gc current block 2-way / gc current block 3-way 대기 이벤트 관찰 가능
  • 2 노드 RAC 의 경우 3-way 메시지를 처리할 필요가 없으므로, 관련 메시지 처리 코드가 최적화 됨
  • 캐시 퓨전 동작이 절대 3 단계를 넘지 않지만, 노드의 수가 증가할수록 3 단계 동작이 발생할 가능성이 증가 하기 때문에 성능에 영향이 발생 할 수도 있다.
구분리소스에 대한 마스터가 될 확률마스터 & 블록 소유 확률비고
3 노드 RAC1/31/22-WAY / 3-WAY
4 노드 RAC1/41/3
  • 3 노드 RAC 테스트 : 각 노드마다 한 개 세션에서 싱글 블록 내의 100 번의 SELECT-AND-UPDATE (매번 커밋) 반복 수행

2-WAY / 3-WAY 동작 테스트


Event					 Waits	Time_outs		 Csec		Avg Csec	 Max Csec
-----					 -----	---------		 ----		--------		-----
gc cr block 2-way			98			0			4			.043			0
gc current block 2-way			98			0			4			.044			0

gc cr block 2-way			49			0			2			.036			2
gc cr block 3-way			47			0			3			.063			0
gc current block 2-way			48			0			2			.033			0
gc current block 3-way			46			0			2			.053			0

gc cr block 2-way			50			0			2			.049			0
gc cr block 3-way			47			0			3			.064			1
gc current block 2-way			50			0			2			.035			0
gc current block 3-way			46			0			2			.051			5

  • 첫번째 세트 : 블록에 대한 마스터 리소스를 소유한 노드 (블록의 가장 최신 버전을 소유하고 있는 노드를 알고 있으므로 항상 2-WAY 동작 수행)
    • gc cr block 2-way : select 에 의한 대기 이벤트
    • gc current block 2-way : update 에 의한 대기 이벤트
  • 두번재,세번째 세트 : 블록 획득을 위해 항상 첫번째 (마스터) 노드에게 물어보고, 첫 번째 노드가 블록을 소유 하고 있으면 2-WAY, 아니면 3-WAY 동작 수행
  • 위 실험을 4 노드 RAC 에 적용 하면, 마스터 노드는 여전히 2-WAY 동작, 나머지 노드는 33 번의 2-WAY, 66번의 3-WAY 동작 발생
  • 위 실험을 통해서 2-WAY 동작 보다 3-WAY 동작이 느림을 알 수 있음

RAC 는 블록 전송시 디스크보다 빠른 네트워크를 활용 함, 이는 RAC 구성 선택에 따른 비용이며 최적화는 필요하나 오버헤드는 아님

CUR (또는 CR) 및 Current 읽기

  • CR 읽기
    • 블록 전송을 요청 받은 노드는 요청 받은 블록이 CR / Current 에 따라 처리 방식이 다름
      • 요청 받은 블록이 Current
        1. 관련 버퍼에 exclusive 모드로 핀 설정
        2. 블록 전송 전 로그 버퍼의 현재 내용을 디스크로 기록 요청 (성능통계 : gc current block pin time, gc current block flush time)
        3. 블록 전송 완료 : 전송 한 블록이 Current 이며 해당 버퍼는 더 이상 Current 가 아니나 PI(Past Image) 상태로 표현
      • Current 복사본을 변경한 후에 인스턴스 장애가 발생하면, PI 블록 이용 가능
      • 한 인스턴스가 current 블록을 디스크에 기록 했다면, PI 를 소유한 모든 인스턴스에게 CR 로 다운그레이드 할 것을 알림
      • 버퍼 확보를 위해 PI FLUSH가 필요하면 current 복사본을 디스크로 기록하라고 메시지를 보냄
      • PI 로 부터 CR 복사본 생성 하지 않고 항상 XCUR 를 소유한 인스턴스에게 메시지를 보내는것 같음
    • Current 복사본을 소유한 인스턴스가 해당 블록에 대한 전송 요청을 받으면, CR 복사본을 생성한 후 전송한다 (성능통계 : gc cr block build time, gc cr block flush time)
  • Current 읽기 - 데이터 버퍼로 읽어 들일 때의 블록의 상태(x$bh.state) 확인
    • 싱글 인스턴스에서 디스크에서 메모리로 블록을 읽어 들일 때, 해당 블록의 상태는 일반적으로 XCUR(exclusive current) 임
      • 블록의 current 버전 이며, 해당 블록을 소유한 인스턴스와 버퍼는 단 하나 이므로, exclusive 이기 때문
    • RAC 에서는 일반적으로 SCUR(shared current) 임
      • 여러 인스턴스가 current 블록의 동일한 복사본을 메모리에 소유할 수 있음 (update 를 통해 메모리로 읽혀진다면 XCUR 상태)

블록들의 상태 확인


SQL> select state, count(*) from x$bh group by state;

-- 가장 흔히 볼 수 있는 상태는 0-free, 1-XCUR, 2-SCUR, 3-CR, 8-PI 임

  • 클러스터 내에 8개의 노드가 존재하고, 8개의 노드 모두 SCUR 모드로 블록을 소유한 상태에서 한 노드가 블록을 변경 하면, 다른 7개의 복사본에는 무슨 일이 발생 하는가?
  • 변경을 수행한 인스턴스는 리소스 마스터를 거쳐 다른 모든 인스턴스에게 CR 로 상태를 변경하라는 메시지 전송

이상현상

alter system flush buffer_cache 수행하면, 모든 인스턴스의 캐시를 flush 한다. 그리고 11.2 에서 PI 블록의 다른 버전이 없다면, PI 블록은 FLUSH 되지 않고 CR 상태로 변경됨. (버그로 추정)