cache fusion 하려면 블록 상태가 exclusive 상태에 있으면 전송 못한다. null모드나 shared모드로 바꿔주고 전송.
----------------------------------------------------------------------------------------------------------------------------------------------
SYS@racdb1> select employee_id, dbms_rowid.rowid_relative_fno(rowid) as file_no,
dbms_rowid.rowid_block_number(rowid) as block_no
from hr.employees
where employee_id in (100,101);
EMPLOYEE_ID FILE_NO BLOCK_NO
----------- ---------- ----------
100 3 31276
101 3 31276
SYS@racdb1> alter system flush buffer_cache;
System altered.
SYS@racdb2> alter system flush buffer_cache;
System altered.
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
update 시
rac2 노드 undo 발생
트랜잭션 발생하는 블록을 데이터 버퍼 캐시에서 찾는다.
없으면 마스터노드에 블록 전송 요청
마스터노드가 GRD를 통해서 어느 노드에 있는지 확인
■ 처음으로 블록을 dml(exclusive)
클러스터 내에서 블록을 최초로 읽어(dml)들이는 노드는 디스크 I/O를 통해 자신의 버퍼 캐시로 블록을 읽게 된다.
HR@racdb2> update hr.employees set salary = salary * 1.1 where employee_id = 100;
1 row updated.
# [3, 31276]
# master node : rac2 node
# request node : rac2 node
물리적 I/O 발생 시 cache buffers lru chain latch를 잡아서 free buffer를 찾고 블록 헤더에 buffer lock을 exclusive모드로 찍는 것까지는 일반 싱글과 똑같다.
수정이 다 되면 바로 해제되는 것도 똑같음.
rac에서의 블록 상태는 null모드.cache fusion을 위함.
1) rac2 노드에 접속한 사용자가 [3, 31276] 블록을 쓰기 요청한다.
해당 블록을 null모드로 획득한다.
2) rac1 노드는 [3, 31276] 블록의 마스터 노드인 rac2 노드에게 블록 전송을 요청한다.
요청 후 응답이 올 때까지는 gc current request 이벤트로 대기한다.(global cache current request)
3) 마스터 노드인 rac2 노드는 GRD를 [3, 31276] 블록을 체크하는데 어떤 인스턴스도 [3, 31276] 블록을 버퍼 캐시에 가지고 있지 않다는 것을
확인하면 rac2 마스터 노드는 rac2 노드에게 [3, 31276] 블록을 공유 모드로 블록을 버퍼 캐시에 적재할 수 있는 권한을 부여한다.
요청한 노드는 gc current grant 2-way 이벤트로 대기한다.
4) 권한을 받은 rac1 노드는 [3, 31276] 블록을 디스크에서 읽어 들인다.
이때 db file sequential read 대기 이벤트가 발생한다.(블록 하나 올리고 읽을 때(single block I/O)의 대기 이벤트)
메모리에 올린 블록은 null모드를 exclusive mode로 변경한다.
5) 마스터 노드인 rac2노드에 GRD에 [3, 31276] 블록의 최신 정보로 갱신한다.
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 xcur 2 1
xcur(eXclusive CURrent) : dml
(MODE_HELD = 2 : exclusive)
LOCAL이 1이면 local, 0이면 global
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
해당 블록이 rac2노드에만 있는 상태. local!
https://docs.oracle.com/en/database/oracle/oracle-database/19/refrn/V-GC_ELEMENT.html
오라클 레퍼런스에서 local의 description이 바뀌어있다. 1이 local, 0이 global이다! 검증을 해봤는데 1이 local임
■ 동일 블록에 대해서 DML(exclusive) commit - select(shared)
# [3, 31276]
# master node : rac2 node
# hold node : rac2 node(exclusive)
# request node : rac1 node(shared)
1) rac1 노드에서 [3, 31276] 블록에 대해 읽기 위해서 마스터 노드에게 해당 블록을 요청한ㄷㅏ.
블록 상태 null모드 상태
rac1 노드는 응답이 올 때까지 gc cr request 이벤트로 대기한다.
2) 요청 받은 마스터 노드는 해당 블록의 최신 정보를 GRD를 통해서 조회한다.
대상 블록이 rac2 노드가 exclusive모드로 가지고 있다는 것을 확인했다.
3) rac2 노드에게 rac1 노드로 전송하도록 요청
4) rac2 노드는 [3, 31276] 블록에 대해서 exclusive 모드를 shared 모드로 다운그레이드한 후 해당 블록을 rac1 노드로 전송한다.
단, 전송하는 대상 블록은 null모드로 전송한다.
# _fairness_threshold : exclusive모드로 획득한 블록에 대해 shared모드로 전송하는 작업을 적당한 횟수만큼 지연하게끔 동작한다.
5) 전송 받은 rac1 노드는 [3, 31276] 블록에 대해서 null모드로 있다.
HR@racdb2> update hr.employees set salary = salary * 1.1 where employee_id = 100;
1 row updated.
HR@racdb2> commit;
Commit complete.
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 xcur 2 1
rac2노드에 대상 블록 exclusive 모드로 되어있음.
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
rac1노드에는 대상 블록이 없음. null모드.
1) rac1 노드에서 select문 조회
HR@racdb1> select * from hr.employees where employee_id = 101;
2) rac2노드에서 exclusive모드로 되어있던 대상 블록을 shared모드로 다운그레이드 시켜서 rac1노드에 전송
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 scur 1 0
3) rac1은 [3, 31276] 블록이 그대로 null모드. _fairness_threshold 파라미터 값만큼 null모드로 그대로 지연시킨다.
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
SYS@racdb1> select a.ksppinm parameter, b.ksppstvl value
from x$ksppi a, x$ksppcv b
where a.indx = b.indx
and a.ksppinm = '_fairness_threshold';
PARAMETER VALUE
------------------------------ ----------
_fairness_threshold 2
# _fairness_threshold : exclusive모드로 획득한 블록에 대해 shared모드로 전송하는 작업을 적당한 횟수만큼 지연하게끔 동작한다.
cache fusion의 문제는 exclusive모드로 되어있는 블록을 전송 못한다는 것.
이 밸류값이 너무 크게 되어있으면 그만큼 요청을 해야지 바뀌니까 비용이 많이 든다.
4) rac1 노드에서 두 번째로 select문 실행
HR@racdb1> select * from hr.employees where employee_id = 102;
EMPLOYEE_ID FIRST_NAME LAST_NAME EMAIL PHONE_NUMBER HIRE_DATE JOB_ID SALARY COMMISSION_PCT MANAGER_ID DEPARTMENT_ID
----------- -------------------- ------------------------- ------------------------- -------------------- --------- ---------- ---------- -------------- ---------- -------------
102 Lex De Haan LDEHAAN 515.123.4569 13-JAN-01 AD_VP 17000 100 90
5) rac2 노드에서 대상 블록 그대로 shared 모드
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000080FB37B0 scur 1 0
6) rac1 노드에서는 대상 블록이 null모드에서 shared 모드로 바뀌었다.
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 scur 1 0
■ 동일 블록에 대해서 DML(exclusive, transaction 진행중 상태) - select(shared)
# [3, 31276]
# master node : rac2 node
# hold node : rac2 node(exclusive)
# request node : rac1 node(shared)
1) rac1 노드에서 [3, 31276] 블록을 마스터 노드에게 읽기 요청한다.
응답이 올 때까지 gc cr request 이벤트로 대기한다.
블록 상태는 null모드이다.
2) 마스터 노드는 GRD를 통해 [3, 31276] 블록을 rac2 노드에서 exclusive 모드로 획득한 상태로 확인
3) 마스터 노드는 rac2 노드에게 [3, 31276] 블록을 rac1 노드로 전송하도록 요청한다.
요청 받은 rac2 노드는 [3, 31276] 블록이 transaction 진행 중인 상태이기 때문에 CR(Consistent Read) 블록 이미지를 생성한 후
rac1 노드로 전송한다.
4) rac1 노드는 전송 받은 CR(consistent Read) 블록의 이전값으로 되돌리기 위한 작업을 진행한다.
즉, rac2 노드에 있는 undo 정보를 이용해서 트랜잭션 발생 전 시점으로 블록의 모습을 만든다.
rac2 노드에서 dml문 트랜잭션 종료하지 않았을 때 값이 변경된 대상 블록의 복제본인 cr block을 만든다. 이 cr block을 rac1 노드로 전송.
트랜잭션이 진행중인 상태에 변경된 블록을 보여줄 수 없어서 rac1 노드에서 cr block을 전송 받아 rac2의 undo블록에서 변경 전 값을 가져와 cr block에 적용.
rac1 노드에서는 rac2 노드의 undo에서 가져온 변경 전 값을 보여준다.
=> 읽기 일관성
I/O는 변경된 수만큼 나옴.
null모드는 재사용된 블록이 될 수 있다.
SYS@racdb1> alter system flush buffer_cache;
System altered.
SYS@racdb2> alter system flush buffer_cache;
System altered.
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
HR@racdb2> update hr.employees set salary = salary * 1.1 where employee_id = 100;
1 row updated.
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 xcur 2 1
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
HR@racdb2> select salary from hr.employees where employee_id = 100;
SALARY
----------
26400
HR@racdb1> select salary from hr.employees where employee_id = 100; -- 커밋하기 전이니 이전 값을 보여줌.
SALARY
----------
24000
rac2의 cr블록(변경된 복제블록)을 rac1로 전송해서 rac1노드의 lms한테 rac2의 언두를 보고 이전 값으로 바꿔!
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
HR@racdb1> select salary from hr.employees where employee_id = 101;
SALARY
----------
17000
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 xcur 2 1
HR@racdb1> update hr.employees set salary = salary * 1.1 where employee_id = 101;
1 row updated.
HR@racdb1> select salary from hr.employees where employee_id = 101;
SALARY
----------
18700
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276; -- exclusive모드의 블록은 전송 안 되므로 null모드로 바꿔서 rac1에 전송함.
no rows selected
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000080FB37B0 xcur 2 1
HR@racdb2> select salary from hr.employees where employee_id = 100;
SALARY
----------
26400
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000080FB37B0 scur 1 0
HR@racdb2> select salary from hr.employees where employee_id = 100;
SALARY
----------
26400
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 scur 1 1
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000080FB37B0 scur 1 1
HR@racdb1> rollback;
Rollback complete.
HR@racdb2> rollback;
Rollback complete.
HR@racdb1> select salary from hr.employees where employee_id = 101;
HR@racdb2> select salary from hr.employees where employee_id = 100;
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000080FB37B0 pi 0 0
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 xcur 2 0
---------------------------------------------------------------------------
■ 동일 블록에 대해서 DML(exclusive, transaction 진행중 상태) - DML(exclusive, transaction 진행중 상태)
# [3, 31276] -- 서로 다른 row지만, 같은 블록
# master node : rac2 node
# hold node : rac2 node(exclusive)
# request node : rac1 node(exclusive)
1) rac1 노드는 [3, 31276] 블록을 마스터 노드에게 쓰기 요청을 한다.
응답이 올 때까지 gc current request 이벤트로 대기한다.
블록은 null모드 상태
2) 요청 받은 마스터 노드는 [3, 31276] 블록이 rac2 노드에서 exclusive 모드인 상태 확인.
클러스터 내에서 같은 블록의 exclusive 모드 상태는 단 하나만 존재해야 한다.
3) rac2 노드는 [3, 31276] 블록을 exclusive모드에서 null모드로 다운그레이드 하기 전에 PI(Past Image, 과거 이미지, 글로벌 dirty buffer) 블록을 생성한 후 리두 로그 파일에 write 작업을 한다.
4) rac2 노드는 [3, 31276] 블록을 rac1 노드로 전송한다.
5) 전송 받은 rac1 노드는 [3, 31276] 블록을 null모드에서 exclusive모드로 획득한다.
6) 마스터 노드는 [3, 31276] 블록에 대한 최신 정보를 갱신한다.
SYS@racdb1> alter system flush buffer_cache;
System altered.
SYS@racdb2> alter system flush buffer_cache;
System altered.
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
no rows selected
HR@racdb2> update hr.employees set salary = salary * 1.1 where employee_id = 100;
1 row updated.
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 xcur 2 1 -- 여기 이 부분이 null이 아닌 게 의아하다.
HR@racdb1> update hr.employees set salary = salary * 1.1 where employee_id = 101;
1 row updated.
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000080FB37B0 xcur 2 0
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 pi 0 0 (null모드로 바꾸기 위해서는 pi가 먼저 나와야 함.)
HR@racdb2> rollback;
Rollback complete.
HR@racdb2> select salary from hr.employees where employee_id = 100;
SYS@racdb2> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000082FF8090 xcur 2 0
HR@racdb1> rollback;
Rollback complete.
HR@racdb1> select salary from hr.employees where employee_id = 101;
SYS@racdb1> select b.lock_element_addr, b.status, e.mode_held, e.local
from v$bh b, v$gc_element e
where b.lock_element_addr = e.gc_element_addr
and b.file# = 3
and b.block# = 31276;
LOCK_ELEMENT_ADD STATUS MODE_HELD LOCAL
---------------- ---------- ---------- ----------
0000000080FB37B0 xcur 2 0
변경된 블록을 redo log file에 전송. 이게 pi.(트랜잭션이 진행되는 상태라서 null모드로 바꾸기 위해서 함. 리두 로그 파일에 먼저 저장하고 블록을 null모드로 바꿈.)
싱글보다 비용 더 많이 발생한다.
* cr block은 rac에서만 나오는 게 아니라 싱글에서도 cr block이 나온다. undo 정보를 가져와서 cr block에 적용하는 것. 읽기 일관성!!!
'강남 아이티윌 오라클DBA과정 94기 > RAC' 카테고리의 다른 글
| [오라클 DBA 과정] 90일차 RAC(7) (2026-07-28) (0) | 2026.07.29 |
|---|---|
| [오라클 DBA 과정] 89일차 RAC(6) (2026-07-27) (0) | 2026.07.27 |
| [오라클 DBA 과정] 87일차 RAC(4) (2026-07-23) (0) | 2026.07.23 |
| [오라클 DBA 과정] 86일차 RAC(3) (2026-07-22) (0) | 2026.07.22 |
| [오라클 DBA 과정] 85일차 RAC(2)(RAC 설치(2)) (2026-07-21) (0) | 2026.07.21 |