My Books

My Slides

rss 아이콘 이미지

Search

'RAC'에 해당되는 글 26건

  1. 2016.08.12 [캐시 퓨전 #5] 커밋된 블록 UPDATE 시에 발생하는 gc cr/current block 2-way, 3-way 대기이벤트에 대한 이해
  2. 2016.08.12 [캐시 퓨전 #4] 변경된 블록 UPDATE 시에 발생하는 gc cr block busy, gc cr/current block 2-way, 3way 대기이벤트에 대한 이해
  3. 2016.08.12 [캐시 퓨전 #3] 커밋된 블록 SELECT 시에 발생하는 gc cr/current block 2-way, 3-way 대기이벤트 및 _fairness_threshold 파라미터에 대한 이해
  4. 2016.08.12 [캐시 퓨전 #2] 변경중인 블록 SELECT 시에 발생하는 gc cr block busy 대기이벤트 및 _db_block_max_cr_dba 파라미터에 대한 이해
  5. 2016.08.12 [캐시 퓨전 #1] SELECT 시에 발생하는 gc cr grant 2-way 대기이벤트에 대한 이해
  6. 2016.08.07 [20] GCS SHADOW 동작 원리 및 GCS SHADOW의 필요성에 대한 설명
  7. 2016.08.02 [19] 블록 마스터 노드 분산에 따른 gc cr grant 2-way 문제 가능성 및 해결 방안
  8. 2016.08.02 [18] 블록 마스터 해싱과 관련된 _lm_contiguous_res_count 파라미터 동작 방식 확인
  9. 2016.08.02 [17] RAC GRD 개요
  10. 2016.07.29 [16] X$BH, X$LE, X$KJBL을 이용한 마스터 노드 확인 방법
  11. 2016.07.26 [15] RAC Interconnect, HAIP에 대한 가벼운 정리
  12. 2016.07.19 [14] ASM 환경에서 ASM 인스턴스, ASMB, RBAL, ARB에 대한 가벼운 정리 (1)
  13. 2016.07.14 [13] UCP 기반의 FCF (Fast Connection Failover) 설명
  14. 2016.07.09 [12] Jmeter + 톰캣 + UCP를 이용한 RLB (Runtime Load Balancing) 동작 방식 검증
  15. 2016.07.09 [11] 톰캣 서버에 UCP (Universal Connection Pool) 구성 및 JSP 샘플 코드 작성
  16. 2016.07.08 [10] CLB, RLB를 위한 서비스 매트릭스 정보의 흐름
  17. 2016.07.07 [09] Connection Load Balancing (CLB)과 Runtime Connection Load Balancing (RLB) 설명
  18. 2016.07.01 [08] V$SERVICEMETRIC, V$SERVICEMETRIC_HISTORY 뷰를 이용한 서비스 성능관리 방안
  19. 2016.06.30 [07] 소스 수정없이 Connection Pool 별로 성능 현황 및 이력을 확인하는 방법
  20. 2016.06.28 [06] 톰캣 JDBC Connection Pool 설정 및 테스트용 JSP 코드 작성

1. 테스트 개요


2번 노드에서 레코드 1건 (마스터 노드: 3번)을 변경한 후 커밋을 수행합니다. 그런 후에 해당 블록 내의 각기 다른 레코드를 1번 및 3번 노드에서 변경합니다. 이를 통해, 커밋된 블록을 변경할 때 발생하는 gc cr block 2-way, gc cr block 3-way, gc current block 2-way, gc current block 3-way 대기이벤트의 동작원리를 파악하도록 합니다.



2. 2번 노드에서 1건 UPDATE 및 COMMIT 수행


2번 노드에서 1건을 변경하면 해당 블록에 대한 XCUR 버퍼 및 CR 버퍼가 캐시에 적재됩니다. (그림-1 참조) 이때 발생하는 변경 사항은 아래의 테스트 결과 중간중간에 주석으로 설명해 두었습니다. (테스트 수행 전에 버퍼 캐시를 flush합니다)


그림-1. 2번 노드에서 1건 UPDATE 및 COMMIT 수행 후의 변경 내용


-- 해당 블록은 로컬 및 리모트 캐시에 존재하지 않으므로 3번 노드의 LMS로부터 블록 액세스 권한을 부여 받습니다.
-- 이로 인해 'gc cr grant 2-way' 대기이벤트가 1회 발생합니다. 
  
-- 그런 후에, 싱글 블록 IO를 이용해서 해당 블록(File#=6, Block#=228)을 메모리로 적재합니다. 
-- 이때 'db file sequential read' 대기이벤트가 1회 발생합니다.
  
-- 해당 블록을 적재한 후에는 해당 블록을 변경하기 위한 CURRENT 권한을 부여 받아야합니다.
-- 이로 인해 'gc current grant 2-way' 대기이벤트가 1회 발생합니다.
  
-- 또한, 변경 작업을 위한 언두 블록을 할당 받기 위해 'db file sequential read' 대기이벤트가 2회 발생합니다.
-- 블록 덤프를 수행해보면 각각 언두 헤더 블록과 언두 블록임을 알 수 있습니다. 

-- 마지막으로 커밋 수행에 따른 'log file sync' 대기이벤트가 1회 발생합니다.

SCOTT@OOW2:2> @set_trace_on 10046 8
SCOTT@OOW2:2> @one_row_update1 

WAIT #140225505518032: nam='gc cr grant 2-way' ela= 1694 p1=6 p2=228 p3=1 obj#=93973 tim=310683117658
WAIT #140225505518032: nam='db file sequential read' ela= 1004 file#=6 block#=228 blocks=1 obj#=93973 tim=310683118769
WAIT #140225505518032: nam='gc current grant 2-way' ela= 1585 p1=6 p2=228 p3=33619969 obj#=93973 tim=310683120612
WAIT #140225505518032: nam='db file sequential read' ela= 4967 file#=5 block#=208 blocks=1 obj#=0 tim=310683125736
WAIT #140225505518032: nam='db file sequential read' ela= 4138 file#=5 block#=3097 blocks=1 obj#=0 tim=310683130557

WAIT #140225502776168: nam='log file sync' ela= 3259 buffer#=3054 sync scn=12152221 p3=0 obj#=0 tim=310702054641

SYS@OOW2:2> alter system dump datafile 5 block 208;
frmt: 0x02 chkval: 0xbae3 type: 0x26=KTU SMU HEADER BLOCK

SYS@OOW2:2> alter system dump datafile 5 block 3097;
frmt: 0x02 chkval: 0xfdae type: 0x02=KTU UNDO BLOCK

-- V$SESSTAT 뷰의 변경 사항 (참고만 하세요)

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      2 [FG]   [EVENT]  db file sequential read            3
                        gc cr grant 2-way                  1
                        gc current grant 2-way             1						
               [STAT]   physical reads                     3
                        session logical reads              3

-- 2번 노드에 XCUR 버퍼 1개와 CR 버퍼 1개가 적재되었습니다.
-- 그리고 2번 노드의 GRD에 GCS 클라이언트 (락 엘리먼트 존재)가 1개 생성되고 
-- 마스터 노드인 3번 노드에 GCS SHADOW가 1개 생성되었습니다.

SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW2 00007F79DD4D06B0      1 CR     00                        0 0000000073540000
     00007F79DD4D0830      1 XCUR   00000000753FD2B0          2 0000000073A8E000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000753FD338      1 KJUSEREX  GRANTED    00000000753FD2B0      1 XCUR
OOW3 00000000696D69C0      1 KJUSEREX  GRANTED



3. 1번 노드에서 동일 블록 내의 다른 레코드 UPDATE 및 COMMIT 수행


1번 노드에서 동을 블록 내의 다른 레코드를 변경하면 2번 노드의 XCUR 버퍼는 PI 버퍼로 변경되고 1번 노드에 XCUR 버퍼가 적재됩니다. (그림-2 참조)


그림-2. 1번 노드에서 동일 블록 내의 다른 레코드 UPDATE 및 COMMIT 수행후의 변경 내용


-- 2번 노드로부터 CR 버퍼와 CURRENT 버퍼를 각각 1개씩 전송 받습니다. 해당 블록의 마스터 노드는 3번이므로 
-- 'gc cr block 3-way'와 'gc current block 3-way' 대기이벤트가 1회씩 발생합니다.

-- 그리고, 트랜잭션 수행을 위한 언두 헤더 블록과 언두 블록을 메모리로 적재하는 과정에서
-- 'db file sequential read' 대기이벤트가 2회 발생합니다.

-- 마지막으로 커밋 수행에 따른 'log file sync' 대기이벤트가 1회 발생합니다. 
  
SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_update2 

WAIT #139902827416192: nam='gc cr block 3-way' ela= 2424 p1=6 p2=228 p3=1 obj#=93973 tim=337578449818
WAIT #139902827416192: nam='gc current block 3-way' ela= 2505 p1=6 p2=228 p3=33554433 obj#=93973 tim=337578453388
WAIT #139902827416192: nam='db file sequential read' ela= 1202 file#=4 block#=192 blocks=1 obj#=0 tim=337578455469
WAIT #139902827416192: nam='db file sequential read' ela= 1351 file#=4 block#=1474 blocks=1 obj#=0 tim=337578457287

WAIT #139902827440960: nam='log file sync' ela= 2514 buffer#=6901 sync scn=12156733 p3=0 obj#=0 tim=337578468566


-- 2번 노드의 LMS가 CR 버퍼와 CURRENT 버퍼를 각각 1개씩 전송한 것을 알 수 있습니다. 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  db file sequential read            2
                        gc cr block 3-way                  1
                        gc current block 3-way             1						
               [STAT]   gc cr blocks received              1
                        gc current blocks received         1
                        physical reads                     2
                        session logical reads              5						
      2 [LMS]  [STAT]   gc cr blocks served                1
                        gc current blocks served           1
                        session logical reads              1

-- 2번 노드의 버퍼 상태가 XCUR에서 PI로 변경되었습니다.
-- 1번 노드에 XCUR 및 CR 버퍼가 1개씩 적재되었습니다.
-- 1번 노드의 GRD에 GCS 클라이언트가 1개 생성되었고, 3번 노드의 GRD에 GCS SHADOW가 1개 생성되었습니다.
	  
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F8072042788      1 CR     00                        0 00000000751CC000
     00007F8072042908      1 XCUR   0000000073BE8BA8          1 0000000074910000

OOW2 00007F79DD4D06B0      1 CR     00                        0 0000000073540000
     00007F79DD4D0830      1 PI     00000000753FD2B0          2 0000000073A8E000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 0000000073BE8C30      0 KJUSEREX  GRANTED    0000000073BE8BA8      1 XCUR
OOW2 00000000753FD338      1 KJUSERNL  GRANTED    00000000753FD2B0      1 PI
OOW3 00000000696D69C0      1 KJUSERNL  GRANTED
OOW3 0000000069728E78      0 KJUSEREX  GRANTED



4. 3번 노드에서 동일 블록 내의 다른 레코드 UPDATE 및 COMMIT 수행


3번 노드에서 동일 블록 내의 다른 레코드를 변경하면 1번 노드의 XCUR 버퍼는 PI 버퍼로 변경되고 3번 노드에 XCUR 버퍼가 적재됩니다. (그림-3 참조)


그림-3. 3번 노드에서 동일 블록 내의 다른 레코드 UPDATE 및 COMMIT 수행후의 변경 내용


-- 1번 노드로부터 CR 버퍼와 CURRENT 버퍼를 각각 1개씩 전송 받습니다. 해당 블록의 마스터 노드는 3번이므로 
-- 'gc cr block 2-way'와 'gc current block 2-way' 대기이벤트가 1회씩 발생합니다.

-- 그리고, 트랜잭션 수행을 위한 언두 헤더 블록과 언두 블록을 메모리로 적재하는 과정에서
-- 'db file sequential read' 대기이벤트가 2회 발생합니다.

-- 마지막으로 커밋 수행에 따른 'log file sync' 대기이벤트가 1회 발생합니다. 

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_update3

WAIT #140357041043368: nam='gc cr block 2-way' ela= 2111 p1=6 p2=228 p3=1 obj#=93973 tim=311326241579
WAIT #140357041043368: nam='gc current block 2-way' ela= 2687 p1=6 p2=228 p3=33554433 obj#=93973 tim=311326245126
WAIT #140357041043368: nam='db file sequential read' ela= 2116 file#=2 block#=160 blocks=1 obj#=0 tim=311326247918
WAIT #140357041043368: nam='db file sequential read' ela= 4200 file#=2 block#=2335 blocks=1 obj#=0 tim=311326252599

WAIT #140357041184600: nam='log file sync' ela= 3590 buffer#=5594 sync scn=12156920 p3=0 obj#=0 tim=311326263131

-- 1번 노드의 LMS가 CR 버퍼와 CURRENT 버퍼를 각각 1개씩 전송한 것을 알 수 있습니다. 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [LMS]  [STAT]   gc cr blocks served                1
                        gc current blocks served           1
                        session logical reads              1						
      3 [FG]   [EVENT]  db file sequential read            2
                        gc cr block 2-way                  1
                        gc current block 2-way             1						
               [STAT]   gc cr blocks received              1
                        gc current blocks received         1
                        physical reads                     2
                        session logical reads              5

-- 1번 노드의 버퍼 상태가 XCUR에서 PI로 변경되었습니다.
-- 3번 노드에 XCUR 및 CR 버퍼가 1개씩 적재되었습니다.
-- 3번 노드의 GRD에 GCS 클라이언트가 1개 생성되었습니다.
						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F80728C39A0      1 CR     00                        0 00000000751CC000
     00007F80728C3B20      1 PI     0000000073BE8BA8          1 0000000074910000

OOW2 00007F79DD4D06B0      1 CR     00                        0 0000000073540000
     00007F79DD4D0830      1 PI     00000000753FD2B0          2 0000000073A8E000

OOW3 00007FBB2D2152B8      1 CR     00                        0 0000000074962000
     00007FBB2D215438      1 XCUR   00000000757E6AD8          1 00000000745BE000


     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 0000000073BE8C30      0 KJUSERNL  GRANTED    0000000073BE8BA8      1 PI
OOW2 00000000753FD338      1 KJUSERNL  GRANTED    00000000753FD2B0      1 PI
OOW3 0000000069728E78      0 KJUSERNL  GRANTED
OOW3 00000000696D69C0      1 KJUSERNL  GRANTED
OOW3 00000000757E6B60      2 KJUSEREX  GRANTED    00000000757E6AD8      1 XCUR


이전: [캐시 퓨전 #4] 변경된 블록 UPDATE 시에 발생하는 gc cr block busy, gc cr/current block 2-way, 3way 대기이벤트에 대한 이해


연재를 마무리하며


5개의 연재를 통해서 캐시 퓨전의 기본 원리에 대해서 살펴보았습니다. 다음 시간에는 경합에 의해 발생하는 buffer busy와 관련된 사항에 대해서 설명할 예정입니다.

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

1. 테스트 개요


2번 노드에서 레코드 1건 (마스터 노드: 3번)을 변경합니다. 그런 후에 해당 블록 내의 각기 다른 레코드를 1번 노드 및 3번 노드에서 변경합니다. 이를 통해, 변경 중인 블록을 변경할 때 발생하는 gc cr block busy, gc cr block 2-way, gc cr block 3-way, gc current block 2-way, gc current block 3-way 대기이벤트의 동작원리를 파악하도록 합니다.



2. 2번 노드에서 1건 UPDATE


2번 노드에서 1건을 변경하면 해당 블록에 대한 XCUR 버퍼 및 CR 버퍼가 캐시에 적재됩니다. (그림-1 참조) 이때 발생하는 변경 사항은 아래의 테스트 결과 중간중간에 주석으로 설명해 두었습니다. (테스트 수행 전에 버퍼 캐시를 flush합니다)


그림-1. 2번 노드에서 1건 변경 후의 버퍼 캐시 변경 내용


-- 해당 블록은 로컬 및 리모트 캐시에 존재하지 않으므로 3번 노드의 LMS로부터 블록 액세스 권한을 부여 받습니다.
-- 이로 인해 'gc cr grant 2-way' 대기이벤트가 1회 발생합니다. 
 
-- 그런 후에, 싱글 블록 IO를 이용해서 해당 블록(File#=6, Block#=228)을 메모리로 적재합니다. 
-- 이때 'db file sequential read' 대기이벤트가 1회 발생합니다.
 
-- 해당 블록을 적재한 후에는 해당 블록을 변경하기 위한 CURRENT 권한을 부여 받아야합니다.
-- 이로 인해 'gc current grant 2-way' 대기이벤트가 1회 발생합니다.
 
-- 또한, 변경 작업을 위한 언두 블록을 할당 받기 위해 'db file sequential read' 대기이벤트가 2회 발생합니다.
-- 블록 덤프를 수행해보면 각각 언두 헤더 블록과 언두 블록임을 알 수 있습니다. 

SCOTT@OOW2:2> @set_trace_on 10046 8
SCOTT@OOW2:2> @one_row_update1 

WAIT #140225505525552: nam='gc cr grant 2-way' ela= 1818 p1=6 p2=228 p3=1 obj#=93973 tim=394675630649
WAIT #140225505525552: nam='db file sequential read' ela= 2100 file#=6 block#=228 blocks=1 obj#=93973 tim=394675632854
WAIT #140225505525552: nam='gc current grant 2-way' ela= 3294 p1=6 p2=228 p3=33619969 obj#=93973 tim=394675636305
WAIT #140225505525552: nam='db file sequential read' ela= 3964 file#=5 block#=240 blocks=1 obj#=0 tim=394675640394
WAIT #140225505525552: nam='db file sequential read' ela= 1170 file#=5 block#=245 blocks=1 obj#=0 tim=394675641954

SYS@OOW2:2> alter system dump datafile 5 block 240;
frmt: 0x02 chkval: 0xbae3 type: 0x26=KTU SMU HEADER BLOCK

SYS@OOW2:2> alter system dump datafile 5 block 245;
frmt: 0x02 chkval: 0xfdae type: 0x02=KTU UNDO BLOCK

-- V$SESSTAT 뷰의 변경 사항 (참고만 하세요)

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      2 [FG]   [EVENT]  db file sequential read            3
                        gc cr grant 2-way                  1
                        gc current grant 2-way             1 						
               [STAT]   physical reads                     3
                        session logical reads              4

-- 2번 노드에 XCUR 버퍼 1개와 CR 버퍼 1개가 적재되었습니다.
-- 그리고 2번 노드의 GRD에 GCS 클라이언트 (락 엘리먼트 존재)가 1개 생성되고 
-- 마스터 노드인 3번 노드에 GCS SHADOW가 1개 생성되었습니다. 
						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW2 00007F79DD4C9118      1 CR     00                        0 0000000074726000
     00007F79DD4C9298      1 XCUR   00000000753FD2B0          2 0000000074AE8000


     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000753FD338      1 KJUSEREX  GRANTED    00000000753FD2B0      1 XCUR
OOW3 00000000696DCCA8      1 KJUSEREX  GRANTED



3. 1번 노드에서 동일 블록 내의 다른 레코드 업데이트


1번 노드에서 동을 블록 내의 다른 레코드를 변경하면 2번 노드의 XCUR 버퍼는 PI 버퍼로 변경되고 1번 노드에 XCUR 버퍼가 적재됩니다. (그림-2 참조)


그림-2. 1번 노드에서 1건 변경 후의 버퍼 캐시 변경 내용


-- 해당 블록은 현재 변경 전 (COMMIT 전이므로 'busy'상태)입니다.
-- 따라서 'gc cr block busy' 대기이벤트가 1회 발생합니다. 

-- 해당 블록에 대한 변경 작업을 수행해야하므로 CURRENT 버퍼를 전송 받아야합니다.
-- 해당 블록의 마스터 노드는 3번 노드이고 현재 2번 노드에 존재하므로
-- 'gc cuurent block 3-way' 대기이벤트가 1회 발생합니다. 

-- 또한, 변경 작업을 위한 언두 블록을 할당 받기 위해 'db file sequential read' 대기이벤트가 2회 발생합니다.

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_update2 

WAIT #139902824629120: nam='gc cr block busy' ela= 10832 p1=6 p2=228 p3=1 obj#=93973 tim=334535308571
WAIT #139902824629120: nam='gc current block 3-way' ela= 4535 p1=6 p2=228 p3=33554433 obj#=93973 tim=334535313580
WAIT #139902824629120: nam='db file sequential read' ela= 3131 file#=4 block#=176 blocks=1 obj#=0 tim=334535317648
WAIT #139902824629120: nam='db file sequential read' ela= 2645 file#=4 block#=1738 blocks=1 obj#=0 tim=334535320442

WAIT #139902827416192: nam='gc cr block busy' ela= 5942 p1=6 p2=228 p3=1 obj#=93973 tim=421043266066
WAIT #139902827416192: nam='gc current block 3-way' ela= 3107 p1=6 p2=228 p3=33554433 obj#=93973 tim=421043269474
WAIT #140357041043368: nam='db file sequential read' ela= 3131 file#=4 block#=240 blocks=1 obj#=0 tim=421043270380
WAIT #139902827416192: nam='db file sequential read' ela= 3960 file#=4 block#=697 blocks=1 obj#=0 tim=421043274340

-- 1번 노드의 Foreground 프로세스는 CR 버퍼와 CURRENT 버퍼를 각각 1개씩 전송 받았음을 알 수 있습니다. 
-- 2번 노드의 LMS는 CR 버퍼를 1개 생성했고, XCUR 버퍼를 PI 버퍼로 변경하기 위해 
-- 'gc cr blocks flushed'를 1회 수행했습니다. 
-- 또한, CR 버퍼와 CURRENT 버퍼를 각각 1개씩 전송한 것을 알 수 있습니다.  

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  db file sequential read            2
                        gc cr block busy                   1
                        gc current block 3-way             1
               [STAT]   gc cr blocks received              1
                        gc current blocks received         1
                        physical reads                     2
                        session logical reads              4
      2 [LMS]  [STAT]   CR blocks created                  1
                        gc cr blocks flushed               1
                        gc cr blocks served                1
                        gc current blocks served           1
                        session logical reads              3

-- 2번 노드의 버퍼 상태가 XCUR에서 PI로 변경되었고, CR 버퍼가 1개 적재되었습니다.
-- 1번 노드에 XCUR 및 CR 버퍼가 1개씩 적재되었습니다.
-- 1번 노드의 GRD에 GCS 클라이언트가 1개 생성되었고, 3번 노드의 GRD에 GCS SHADOW가 1개 생성되었습니다.
						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F80728C2FD0      1 CR     00                        0 000000007518A000
     00007F80728C3150      1 XCUR   00000000757E5958          1 00000000742A6000

OOW2 00007F79DD4FCB10      1 CR     00                        0 00000000749A0000
     00007F79DD4FCC90      1 PI     00000000753FD2B0          2 00000000745C0000
     00007F79DD4FCE10      1 CR     00                        0 000000007451A000


     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 00000000757E59E0      0 KJUSEREX  GRANTED    00000000757E5958      1 XCUR
OOW2 00000000753FD338      1 KJUSERNL  GRANTED    00000000753FD2B0      1 PI
OOW3 00000000696F1F18      0 KJUSEREX  GRANTED
OOW3 00000000696E4610      1 KJUSERNL  GRANTED


4. 3번 노드에서 동일 블록 내의 다른 레코드 업데이트


3번 노드에서 동일 블록 내의 다른 레코드를 변경하면 1번 노드의 XCUR 버퍼는 PI 버퍼로 변경되고 3번 노드에 XCUR 버퍼가 적재됩니다. (그림-3 참조) 이점은 2번 노드에서의 변경과 동일합니다. 하지만 한번 PI 버퍼가 생성된 이후에는 gc cr buffer busy 대기가 아닌 gc cr block 2-way 대기이벤트가 발생합니다. 이것은 이전 시점에 2번 노드의 LMS가 수행한 gc cr blocks flushed의 영향으로 파악됩니다. 그리고 1번, 2번 노드에서 수행한 트랜잭션과 관련된 언두 헤더 블록 및 언두 블록을 전송 받기 위해서 gc cr block 2-way 대기이벤트가 총 4회 발생했습니다.


그림-3. 3번 노드에서 1건 변경 후의 버퍼 캐시 변경 내용


-- 해당 블록 (p1=6 p2=228)에 대한 CR 버퍼와 CURRENT 버퍼를 전송 받는 과정에서 -- 'gc cr block 2-way'와 'gc current block 2-way' 대기이벤트가 각각 1회 발생합니다. -- 1번 노드에서 수행한 트랜잭션과 관련된 언두 헤더 블록 (p1=4 p2=240) -- 및 언두 블록 (p1=4 p2=697)에 대한 CR 버퍼를 전송 받는 과정에서 -- 'gc cr block 2-way' 대기이벤트가 2회 발생합니다. -- 2번 노드에서 수행한 트랜잭션과 관련된 언두 헤더 블록 (p1=5 p2=240) -- 및 언두 블록 (p1=5 p2=235)에 대한 CR 버퍼를 전송받는 과정에서 -- 'gc cr block 2-way' 대기이벤트가 2회 발생합니다. -- 해당 트랜잭션 수행을 위한 언두 헤더 블록과 언두 블록을 할당 받는 과정에서 -- 'db file sequential read' 대기이벤트가 2회 발생합니다. SCOTT@OOW1:1> @set_trace_on 10046 8 SCOTT@OOW1:1> @one_row_update3 WAIT #140357041043368: nam='gc cr block 2-way' ela= 2455 p1=6 p2=228 p3=1 obj#=93973 tim=394694643881 WAIT #140357041043368: nam='gc cr block 2-way' ela= 811 p1=4 p2=240 p3=31 obj#=0 tim=394694645290 WAIT #140357041043368: nam='gc cr block 2-way' ela= 1073 p1=5 p2=240 p3=51 obj#=0 tim=394694647769 WAIT #140357041043368: nam='gc cr block 2-way' ela= 3229 p1=4 p2=697 p3=32 obj#=0 tim=394694651686 WAIT #140357041043368: nam='gc cr block 2-way' ela= 1424 p1=5 p2=245 p3=52 obj#=0 tim=394694654291 WAIT #140357041043368: nam='gc current block 2-way' ela= 1088 p1=6 p2=228 p3=33554433 obj#=93973 tim=394694655965 WAIT #140357041043368: nam='db file sequential read' ela= 6037 file#=2 block#=128 blocks=1 obj#=0 tim=394694662551 WAIT #140357041043368: nam='db file sequential read' ela= 1904 file#=2 block#=2540 blocks=1 obj#=0 tim=394694665150 -- 1번 노드의 LMS가 3개의 CR 버퍼와 1개의 CURRENT 버퍼를 전송했습니다. -- 2번 노드의 LMS가 2개의 CR 버퍼를 전송했습니다. SYS@OOW1:1> @init_temp_sesstat 91 65 43 SYS@OOW1:1> @get_temp_sesstat 91 65 43 INST_ID SERVER FLAG NAME VALUE ------- ------ -------- ------------------------------ ----- 1 [LMS] [STAT] gc cr blocks served 3 gc current blocks served 1 session logical reads 3 2 [LMS] [STAT] gc cr blocks served 2 session logical reads 2 3 [FG] [EVENT] db file sequential read 2 gc cr block 2-way 5 gc current block 2-way 1 [STAT] gc cr blocks received 5 gc current blocks received 1 physical reads 2 session logical reads 10 -- 1번 노드의 버퍼 상태가 XCUR에서 PI로 변경되었습니다. -- 3번 노드에 XCUR 및 CR 버퍼가 1개씩 적재되었습니다. -- 3번 노드의 GRD에 GCS 클라이언트가 1개 생성되었습니다. SYS@OOW1:1> @fnd_gcs_detail2 6 228 X$BH X$BH X$BH X$BH INST ADDR CLASS STATE LE_ADDR TCH BA ---- ---------------- ------ ------ ---------------- ---------- ---------------- OOW1 00007F80724285B0 1 CR 00 0 000000007518A000 00007F8072428730 1 PI 00000000757E5958 1 00000000742A6000 OOW2 00007F79DD4D15F0 1 CR 00 0 00000000749A0000 00007F79DD4D1770 1 PI 00000000753FD2B0 2 00000000745C0000 00007F79DD4D18F0 1 CR 00 0 000000007451A000 OOW3 00007FBB2D4168B0 1 CR 00 0 00000000752A6000 00007FBB2D416A30 1 XCUR 00000000757E6AD8 1 000000007494E000 X$KJBL X$KJBL X$KJBL X$KJBL X$BH X$BH X$BH INST LOCKP OWNER GRANT LOCKST LE_ADDR CLASS STATE ---- ---------------- ------ --------- ---------- ---------------- ------ ------ OOW1 00000000757E59E0 0 KJUSERNL GRANTED 00000000757E5958 1 PI OOW2 00000000753FD338 1 KJUSERNL GRANTED 00000000753FD2B0 1 PI OOW3 00000000696E4610 1 KJUSERNL GRANTED OOW3 00000000696F1F18 0 KJUSERNL GRANTED OOW3 00000000757E6B60 2 KJUSEREX GRANTED 00000000757E6AD8 1 XCUR


이전: [캐시 퓨전 #3] 커밋된 블록 SELECT 시에 발생하는 gc cr/current block 2-way, 3-way 대기이벤트 및 _fairness_threshold 파라미터에 대한 이해
다음: [캐시 퓨전 #5] 커밋된 블록 UPDATE 시에 발생하는 gc cr/current block 2-way, 3-way 대기이벤트에 대한 이해

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

1. 테스트 개요


2번 노드에서 레코드 1건 (마스터 노드: 3번)을 변경한 후에 커밋을 수행합니다. 그런 후에 동일 레코드를 1번  및 3번 노드에서 반복적으로 조회합니다. 이를 통해, 커밋된 블록을 조회할 떄 발생하는 gc cr block 2-way, gc cr block 3-way, gc current block 2-way, gc current block 3-way 대기이벤트 및 _fairness_threshold 파라미터의 동작원리를 파악하도록 합니다.



2. 2번 노드에서 1건 UPDATE 및 COMMIT 수행


2번 노드에서 1건을 변경하면 해당 블록에 대한 XCUR 버퍼 및 CR 버퍼가 캐시에 적재됩니다. (그림-1 참조) 이때 발생하는 변경 사항은 아래의 테스트 결과 중간중간에 주석으로 설명해 두었습니다. (테스트 수행 전에 버퍼 캐시를 flush합니다)


그림-1. 2번 노드에서 1건 UPDATE 및 COMMIT 수행 후의 변경 내용


-- 해당 블록은 로컬 및 리모트 캐시에 존재하지 않으므로 3번 노드의 LMS로부터 블록 액세스 권한을 부여 받습니다.
-- 이로 인해 'gc cr grant 2-way' 대기이벤트가 1회 발생합니다. 
 
-- 그런 후에, 싱글 블록 IO를 이용해서 해당 블록(File#=6, Block#=228)을 메모리로 적재합니다. 
-- 이때 'db file sequential read' 대기이벤트가 1회 발생합니다.
 
-- 해당 블록을 적재한 후에는 해당 블록을 변경하기 위한 CURRENT 권하는 부여 받아야합니다.
-- 이로 인해 'gc current grant 2-way' 대기이벤트가 1회 발생합니다.
 
-- 또한, 변경 작업을 위한 언두 블록을 할당 받기 위해 'db file sequential read' 대기이벤트가 2회 발생합니다.
-- 블록 덤프를 수행해보면 각각 언두 헤더 블록과 언두 블록임을 알 수 있습니다. 

-- 마지막으로 커밋 수행에 따른 'log file sync' 대기이벤트가 1회 발생합니다. 

SCOTT@OOW2:2> @set_trace_on 10046 8
SCOTT@OOW2:2> @one_row_update 
SCOTT@OOW2:2> commit; 

WAIT #140225502726824: nam='gc cr grant 2-way' ela= 2572 p1=6 p2=228 p3=1 obj#=93823 tim=291817361860
WAIT #140225502726824: nam='db file sequential read' ela= 5763 file#=6 block#=228 blocks=1 obj#=93823 tim=291817368044
WAIT #140225502726824: nam='gc current grant 2-way' ela= 4572 p1=6 p2=228 p3=33619969 obj#=93823 tim=291817374295
WAIT #140225502726824: nam='db file sequential read' ela= 1795 file#=5 block#=160 blocks=1 obj#=0 tim=291817376480
WAIT #140225502726824: nam='db file sequential read' ela= 2058 file#=5 block#=8099 blocks=1 obj#=0 tim=291817379029
WAIT #140225505518032: nam='log file sync' ela= 2549 buffer#=631 sync scn=12103377 p3=0 obj#=0 tim=291881847246

SYS@OOW2:2> alter system dump datafile 5 block 160;
frmt: 0x02 chkval: 0xbae3 type: 0x26=KTU SMU HEADER BLOCK

SYS@OOW2:2> alter system dump datafile 5 block 8099;
frmt: 0x02 chkval: 0xfdae type: 0x02=KTU UNDO BLOCK  '

-- V$SESSTAT 뷰의 변경 사항 (참고만 하세요)

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      2 [FG]   [EVENT]  db file sequential read            3
                        gc cr grant 2-way                  1
                        gc current grant 2-way             1						
               [STAT]   physical reads                     3
                        session logical reads              8

-- 2번 노드에 XCUR 버퍼 1개와 CR 버퍼 1개가 적재되었습니다.
-- 그리고 2번 노드의 GRD에 GCS 클라이언트 (락 엘리먼트 존재)가 1개 생성되고 
-- 마스터 노드인 3번 노드에 GCS SHADOW가 1개 생성되었습니다. 

SYS@OOW1:1> @fnd_gcs_detail2 6 228
 
                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW2 00007F79DD6859A8      1 CR     00                        0 0000000073474000
     00007F79DD685B28      1 XCUR   00000000737F7900          2 0000000074AFC000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000737F7988      1 KJUSEREX  GRANTED    00000000737F7900      1 XCUR
OOW3 0000000069716EA8      1 KJUSEREX  GRANTED


3. 1번 노드에서 해당 레코드 조회 (1회 수행)


1번 노드에서 동일한 레코드를 조회하면 1번 노드에 해당 블록에 대한 CR 버퍼가 버퍼 캐시에 적재됩니다. (그림-2 참조)


그림-2. 1번 노드에서 해당 레코드 1회 조회한 후의 버퍼 캐시 변경 내용


-- 해당 블록의 마스터 노드는 3번 노드이고 현재 2번 노드에 존재합니다.
-- 따라서 'gc cr block 3-way' 대기이벤트가 1회 발생합니다. 

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select 

WAIT #139902907847544: nam='gc cr block 3-way' ela= 3504 p1=6 p2=228 p3=1 obj#=93823 tim=318327265441

-- 1번 노드의 Foreground 프로세스는 CR 버퍼를 1개 전송 받았음을 알 수 있습니다.
-- 2번 노드의 LMS는 CR 버퍼를 1번 노드로 전송한 것을 알 수 있습니다. 
-- 이때, 연재#2의 경우와 달리 LMS는 CR 버퍼를 생성하지 않습니다. 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  gc cr block 3-way                  1	  
               [STAT]   gc cr blocks received              1
                        session logical reads              1						
      2 [LMS]  [STAT]   gc cr blocks served                1
                        session logical reads              1

-- 1번 노드에 CR 버퍼가 1개 적재되었습니다. 

SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F8072A9E478      1 CR     00                        1 00000000738D0000

OOW2 00007F79E2243540      1 CR     00                        0 000000007490C000
     00007F79E22436C0      1 XCUR   00000000737F7900          2 000000007396E000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000737F7988      1 KJUSEREX  GRANTED    00000000737F7900      1 XCUR
OOW3 000000006971F698      1 KJUSEREX  GRANTED



4. 1번 노드에서 해당 레코드 조회 (2회 수행)


1번 노드에서 동일한 레코드를 한번 더 조회하면 1번 노드의 버퍼 캐시에는 CR 버퍼가 1개 적재됩니다. 그리고 2번 노드의 버퍼 상태가 XCUR에서 SCUR로 변경됩니다. (그림-3 참조) 2번 노드의 버퍼 상태가 SCUR로 변경되는 것은 _fairness_threshold 파라미터와 관련이 있습니다. 해당 파라미터의 설정 값은 버전에 따라 다르고 제 환경에서는 2입니다. 따라서 변경이 끝난 XCUR 버퍼를 2번 액세스하면 버퍼의 상태가 SCUR로 변경됩니다.


그림-3. 1번 노드에서 해당 레코드 2회 조회한 후의 버퍼 캐시 변경 내용


-- 1회 조회 시와 동일하게 'gc cr block 3-way' 대기이벤트가 1회 발생합니다.

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select 

WAIT #139902907847544: nam='gc cr block 3-way' ela= 3470 p1=6 p2=228 p3=1 obj#=93823 tim=319239338492

-- 1회 조회 시와 동일합니다.

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  gc cr block 3-way                  1	  
               [STAT]   gc cr blocks received              1
                        session logical reads              1						
      2 [LMS]  [STAT]   gc cr blocks served                1
                        session logical reads              1

-- 1번 노드에 CR 버퍼 1개가 적재되었습니다.
-- 그리고 2번 노드의 버퍼 상태가 XCUR에 SCUR로 변경되었습니다. 
					
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F8072A485F8      1 CR     00                        1 00000000738D0000
     00007F8072A48778      1 CR     00                        1 000000007382C000

OOW2 00007F79E22436C0      1 CR     00                        0 000000007490C000
     00007F79E2243840      1 SCUR   00000000737F7900          2 000000007396E000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000737F7988      1 KJUSERPR  GRANTED    00000000737F7900      1 SCUR
OOW3 000000006971F698      1 KJUSERPR  GRANTED



5. 1번 노드에서 해당 레코드 조회 (3회 수행)


1번 노드에서 동일한 레코드를 한번 더 조회하면 1번 노드의 버퍼 캐시에는 SCUR 버퍼가 1개 적재됩니다. (그림-4 참조)


그림-4. 1번 노드에서 해당 레코드 3회 조회한 후의 버퍼 캐시 변경 내용


-- SCUR 버퍼가 적재되므로 'gc cr block 3-way'가 아닌 'gc current block 3-way' 대기이벤트가 1회 발생합니다. 

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select 

WAIT #139902907847544: nam='gc current block 3-way' ela= 3935 p1=6 p2=228 p3=1 obj#=93823 tim=319277179034

-- 1번 노드의 Foreground 프로세스는 CURRENT 버퍼를 1개 전송 받았음을 알 수 있습니다.
-- 2번 노드의 LMS는 CURRENT 버퍼를 1번 노드로 전송한 것을 알 수 있습니다. 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  gc current block 3-way             1	  
               [STAT]   gc current blocks received         1
                        session logical reads              1						
      2 [LMS]  [STAT]   gc current blocks served           1

-- 1번 노드에 SCUR 버퍼 1개가 적재되었습니다.
-- 그리고 1번 노드의 GRD에 GCS 클라이언트가 1개 생성되고, 
-- 마스터 노드인 3번 노드의 GRD에 GCS SHADOW가 1개 생성되었습니다.

SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F807277ED78      1 CR     00                        1 00000000738D0000
     00007F807277EEF8      1 CR     00                        1 000000007382C000
     00007F807277F078      1 SCUR   00000000743ECD48          1 0000000073C74000

OOW2 00007F79E22436C0      1 CR     00                        0 000000007490C000
     00007F79E2243840      1 SCUR   00000000737F7900          2 000000007396E000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 00000000743ECDD0      0 KJUSERPR  GRANTED    00000000743ECD48      1 SCUR
OOW2 00000000737F7988      1 KJUSERPR  GRANTED    00000000737F7900      1 SCUR
OOW3 0000000069722410      0 KJUSERPR  GRANTED
OOW3 000000006971F698      1 KJUSERPR  GRANTED



6. 1번 노드에서 해당 레코드 조회 (4회 수행)


1번 노드에도 SCUR 버퍼가 존재하므로, 해당 레코드를 조회하면 로컬 캐시에서 SCUR 버퍼를 읽습니다. 따라서 클러스터 및 IO 관련 대기이벤트 및 GRD 내의 변경은 발생하지 않습니다. 로컬 캐시에서 원하는 블록을 읽었으므로 메모리 IO가 1회 증가하고 해당 버퍼의 TCH가 2로 증가하는 정도의 변경만 발생합니다.


-- 클러스터 및 IO 관련 대기이벤트는 발생하지 않습니다.

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select 

-- 해당 버퍼에 대한 메모리 IO가 1회 발생합니다. 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [STAT]   session logical reads              1

-- SCUR 버퍼에 대한 액세스로 인해 TCH가 2로 증가합니다.
	  
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F807277ED78      1 CR     00                        1 00000000738D0000
     00007F807277EEF8      1 CR     00                        1 000000007382C000
     00007F807277F078      1 SCUR   00000000743ECD48          2 0000000073C74000

OOW2 00007F79E22436C0      1 CR     00                        0 000000007490C000
     00007F79E2243840      1 SCUR   00000000737F7900          2 000000007396E000


     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 00000000743ECDD0      0 KJUSERPR  GRANTED    00000000743ECD48      1 SCUR
OOW2 00000000737F7988      1 KJUSERPR  GRANTED    00000000737F7900      1 SCUR
OOW3 0000000069722410      0 KJUSERPR  GRANTED
OOW3 000000006971F698      1 KJUSERPR  GRANTED



7. 3번 노드에서 해당 레코드 1회 조회


3번 노드에서 동일한 레코드를 조회하면 해당 블록에 대한 SCUR 버퍼가 버퍼 캐시에 적재됩니다. (그림-5 참조)


그림-5. 3번 노드에서 1건 조회 후의 버퍼 캐시 변경 내용


-- 3번 노드가 마스터 노드이고 CUURENT 블록을 전송 받으므로 
-- 'gc current block 2-way' 대기이벤트가 1회 발생합니다.

SCOTT@OOW3:3> @set_trace_on 10046 8
SCOTT@OOW3:3> @one_row_select 

WAIT #140357041936560: nam='gc current block 2-way' ela= 3478 p1=6 p2=228 p3=1 obj#=93973 tim=384133917366

-- 2번 노드의 LMS는 CURRENT 버퍼를 3번 노드로 전송한 것을 알 수 있습니다. 
-- 3번 노드의 Foreground 프로세스는 CURRENT 버퍼를 1개 전송 받았음을 알 수 있습니다.

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      2 [LMS]  [STAT]   gc current blocks served           1
      3 [FG]   [EVENT]  gc current block 2-way             1
               [STAT]   gc current blocks received         1
                        session logical reads              1

-- 3번 노드에 SCUR 버퍼 1개가 적재되었습니다.
-- 그리고 3번 노드의 GRD에 GCS 클라이언트 (락 엘리먼트 존재)가 1개 생성되었습니다.

SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F8072A48030      1 CR     00                        1 0000000074090000
     00007F8072A481B0      1 CR     00                        1 0000000074AEE000
     00007F8072A48330      1 SCUR   0000000074BE0868          2 0000000074752000

OOW2 00007F79DD4C9BE0      1 CR     00                        0 0000000073D54000
     00007F79DD4C9D60      1 SCUR   00000000737F7900          2 0000000072E8E000

OOW3 00007FBB31F8A7D8      1 SCUR   00000000743E5B88          1 0000000073E70000


     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 0000000074BE08F0      0 KJUSERPR  GRANTED    0000000074BE0868      1 SCUR
OOW2 00000000737F7988      1 KJUSERPR  GRANTED    00000000737F7900      1 SCUR
OOW3 00000000696D0390      0 KJUSERPR  GRANTED
OOW3 000000006972A570      1 KJUSERPR  GRANTED
OOW3 00000000743E5C10      2 KJUSERPR  GRANTED    00000000743E5B88      1 SCUR



7. 3번 노드에서 해당 레코드 조회 2회 조회


3번 노드에도 SCUR 버퍼가 존재하므로, 해당 레코드를 조회하면 로컬 캐시에서 SCUR 버퍼를 읽습니다. 따라서 클러스터 및 IO 관련 대기이벤트 및 GRD 내의 변경은 발생하지 않습니다. 로컬 캐시에서 원하는 블록을 읽었으므로 메모리 IO가 1회 증가하고 해당 버퍼의 TCH가 2로 증가하는 정도의 변경만 발생합니다.


-- 클러스터 및 IO 관련 대기이벤트는 발생하지 않습니다.

SCOTT@OOW3:3> @set_trace_on 10046 8
SCOTT@OOW3:3> @one_row_select 

-- 해당 버퍼에 대한 메모리 IO가 1회 발생합니다. 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      3 [FG]   [STAT]   session logical reads              1

-- SCUR 버퍼에 대한 액세스로 인해 TCH가 2로 증가합니다.
	  
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F807277E4E8      1 CR     00                        1 0000000074090000
     00007F807277E668      1 CR     00                        1 0000000074AEE000
     00007F807277E7E8      1 SCUR   0000000074BE0868          2 0000000074752000

OOW2 00007F79DD4C9BE0      1 CR     00                        0 0000000073D54000
     00007F79DD4C9D60      1 SCUR   00000000737F7900          2 0000000072E8E000

OOW3 00007FBB31F8AAD8      1 SCUR   00000000743E5B88          2 0000000073E70000


     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 0000000074BE08F0      0 KJUSERPR  GRANTED    0000000074BE0868      1 SCUR
OOW2 00000000737F7988      1 KJUSERPR  GRANTED    00000000737F7900      1 SCUR
OOW3 00000000696D0390      0 KJUSERPR  GRANTED
OOW3 000000006972A570      1 KJUSERPR  GRANTED
OOW3 00000000743E5C10      2 KJUSERPR  GRANTED    00000000743E5B88      1 SCUR


 

이전: [캐시 퓨전 #2] 변경중인 블록 SELECT 시에 발생하는 gc cr block busy 대기이벤트 및 _db_block_max_cr_dba 파라미터에 대한 이해

다음: [캐시 퓨전 #4] 변경된 블록 UPDATE 시에 발생하는 gc cr block busy, gc cr/current block 2-way, 3way 대기이벤트에 대한 이해

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

1. 테스트 개요


2번 노드에서 레코드 1건 (마스터 노드: 3번)을 변경한 후에 1번 및 3번 노드에서 동일 레코드를 각각 7번 조회합니다. 이를 통해 변경 중인 블록을 조회할 때 발생하는 대기이벤트와 성능 지표를 살펴보고 버퍼 캐시 및 GRD의 변경 내용을 확인합니다. 그리고 _db_block_max_cr_dba 파라미터의 동작원리 또한 파악하도록 합니다.



2. 2번 노드에서 1건 UPDATE


2번 노드에서 1건을 변경하면 해당 블록에 대한 XCUR 버퍼 및 CR 버퍼가 캐시에 적재됩니다. (그림-1 참조) 이때 발생하는 변경 사항은 아래의 테스트 결과 중간중간에 주석으로 설명해 두었습니다. (테스트 수행 전에 버퍼 캐시를 flush합니다)


그림-1. 2번 노드에서 1건 변경 후의 버퍼 캐시 변경 내용


-- 해당 블록은 로컬 및 리모트 캐시에 존재하지 않으므로 3번 노드의 LMS로부터 블록 액세스 권한을 부여 받습니다.
-- 이로 인해 'gc cr grant 2-way' 대기이벤트가 1회 발생합니다. 

-- 그런 후에, 싱글 블록 IO를 이용해서 해당 블록(File#=6, Block#=228)을 메모리로 적재합니다. 
-- 이때 'db file sequential read' 대기이벤트가 1회 발생합니다.

-- 해당 블록을 적재한 후에는 해당 블록을 변경하기 위한 CURRENT 권한을 부여 받아야합니다.
-- 이로 인해 'gc current grant 2-way' 대기이벤트가 1회 발생합니다.

-- 또한, 변경 작업을 위한 언두 블록을 할당 받기 위해 'db file sequential read' 대기이벤트가 2회 발생합니다.
-- 블록 덤프를 수행해보면 각각 언두 헤더 블록과 언두 블록임을 알 수 있습니다. 
 
SCOTT@OOW2:2> @set_trace_on 10046 8
SCOTT@OOW2:2> @one_row_update 

WAIT #140225505518032: nam='gc cr grant 2-way' ela= 1913 p1=6 p2=228 p3=1 obj#=93823 tim=294714258816
WAIT #140225505518032: nam='db file sequential read' ela= 1918 file#=6 block#=228 blocks=1 obj#=93823 tim=294714261240
WAIT #140225505518032: nam='gc current grant 2-way' ela= 2213 p1=6 p2=228 p3=33619969 obj#=93823 tim=294714263898
WAIT #140225505518032: nam='db file sequential read' ela= 2029 file#=5 block#=144 blocks=1 obj#=0 tim=294714268613
WAIT #140225505518032: nam='db file sequential read' ela= 1150 file#=5 block#=1796 blocks=1 obj#=0 tim=294714270377
 
SYS@OOW2:2> alter system dump datafile 5 block 144;
frmt: 0x02 chkval: 0xbae3 type: 0x26=KTU SMU HEADER BLOCK 

SYS@OOW2:2> alter system dump datafile 5 block 1796;
frmt: 0x02 chkval: 0xfdae type: 0x02=KTU UNDO BLOCK 

-- V$SESSTAT 뷰의 변경 사항 (참고만 하세요)

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      2 [FG]   [EVENT]  db file sequential read            3
                        gc cr grant 2-way                  1
                        gc current grant 2-way             1						
               [STAT]   physical reads                     3
                        session logical reads              4

-- 2번 노드에 XCUR 버퍼 1개와 CR 버퍼 1개가 적재되었습니다.
-- 그리고 2번 노드의 GRD에 GCS 클라이언트 (락 엘리먼트 존재)가 1개 생성되고 
-- 마스터 노드인 3번 노드에 GCS SHADOW가 1개 생성되었습니다. 
 						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW2 00007F79DD4C4F08      1 CR     00                        0 00000000734C2000
     00007F79DD4C5088      1 XCUR   00000000733E2EB0          2 000000007513A000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000733E2F38      1 KJUSEREX  GRANTED    00000000733E2EB0      1 XCUR
OOW3 00000000696D70C8      1 KJUSEREX  GRANTED



3. 1번 노드에서 해당 레코드 조회 (1회 수행)


1번 노드에서 동일한 레코드를 조회하면 1번 노드 및 2번 노드에 해당 블록에 대한 CR 버퍼가 버퍼 캐시에 적재됩니다. (그림-2 참조)


그림-2. 1번 노드에서 1건 조회 후의 버퍼 캐시 변경 내용


-- 해당 블록은 현재 변경 전 (COMMIT 전이므로 'busy'상태)입니다.
-- 따라서 'gc cr block busy' 대기이벤트가 1회 발생합니다. 

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select 

WAIT #139902907847544: nam='gc cr block busy' ela= 18363 p1=6 p2=228 p3=1 obj#=93823 tim=311836140232

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

-- 1번 노드의 Foreground 프로세스는 CR 버퍼를 1개 전송 받았음을 알 수 있습니다.
-- 2번 노드의 LMS는 CR 버퍼를 1개 생성한 후에 1번 노드로 해당 버퍼를 전송한 것을 알 수 있습니다. 

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  gc cr block busy                   1
               [STAT]   gc cr blocks received              1
                        session logical reads              1
      2 [LMS]  [STAT]   CR blocks created                  1
                        gc cr blocks flushed               1
                        gc cr blocks served                1
                        session logical reads              3

-- 1번 노드와 2번 노드에 CR 버퍼가 각각 1개씩 더 적재되었습니다. 
						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F8072037AC8      1 CR     00                        1 0000000074298000

OOW2 00007F79DD69C000      1 CR     00                        0 00000000734C2000
     00007F79DD69C180      1 XCUR   00000000733E2EB0          2 000000007513A000
     00007F79DD69C300      1 CR     00                        0 000000007545E000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000733E2F38      1 KJUSEREX  GRANTED    00000000733E2EB0      1 XCUR
OOW3 00000000696D70C8      1 KJUSEREX  GRANTED



4. 1번 노드에서 해당 레코드 조회 (6회 수행)


해당 레코드를 6회 반복해서 조회하면 1, 2번 모두 6개의 CR 버퍼가 적재됩니다. (그림-3 참조) 즉, 'busy'한 블록을 반복적으로 조회하면 조회할 때마다 CR 버퍼가 적재되고, 최대 값은 _db_block_max_cr_dba 파라미터에 의해 결정됩니다. 해당 파라미터의 기본 설정 값은 6이므로 최대 6개의 CR 버퍼가 적재된 것을 알 수 있습니다.


그림-3. 1번 노드에서 6번 조회 후의 버퍼 캐시 변경 내용



-- 해당 블록은 현재 변경 전 (COMMIT 전이므로 'busy'상태)입니다.
-- 따라서 'gc cr block busy' 대기이벤트가 1회 발생합니다. 
 
SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select 

WAIT #139902907847544: nam='gc cr block busy' ela= 4052 p1=6 p2=228 p3=1 obj#=93823 tim=311885751211

-- 이전과 동일하게 2번 노드의 LMS는 CR 버퍼를 1개 생성한 후 1번 노드로 전송한 것을 알 수 있습니다.

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  gc cr block busy                   1
               [STAT]   gc cr blocks received              1
                        session logical reads              1
      2 [LMS]  [STAT]   CR blocks created                  1
                        gc cr blocks flushed               1
                        gc cr blocks served                1
                        session logical reads              3

-- 1,2번 노드 각각 6개의 CR 버퍼가 적재되었습니다. 
						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F80720374A8      1 CR     00                        1 0000000073D70000
     00007F8072037648      1 CR     00                        1 0000000074034000
     00007F80720377C8      1 CR     00                        1 0000000074274000
     00007F8072037948      1 CR     00                        1 0000000074CD0000
     00007F8072037AC8      1 CR     00                        1 00000000739E8000
     00007F807236C5A0      1 CR     00                        1 0000000074298000

OOW2 00007F79DD69BA00      1 XCUR   00000000733E2EB0          2 000000007513A000
     00007F79DD69BB80      1 CR     00                        0 000000007545E000
     00007F79DD69BD00      1 CR     00                        0 0000000075772000
     00007F79DD69BE80      1 CR     00                        0 0000000072EB4000
     00007F79DD69C000      1 CR     00                        0 0000000075038000
     00007F79DD69C180      1 CR     00                        0 00000000734C2000
     00007F79DD69C300      1 CR     00                        0 0000000073194000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000733E2F38      1 KJUSEREX  GRANTED    00000000733E2EB0      1 XCUR
OOW3 00000000696D70C8      1 KJUSEREX  GRANTED



5. 1번 노드에서 해당 레코드 조회 (7회 수행)


그렇다면, 해당 레코드를 7번쨰 조회할 경우에는 어떤 변화가 발생하는지 확인해보겠습니다.

-- 여전히, 'gc cr block busy' 대기이벤트가 발생합니다. 

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select

WAIT #139902907847544: nam='gc cr block busy' ela= 7971 p1=6 p2=228 p3=1 obj#=93823 tim=311953030887

-- 여전히, 2번 노드의 LMS는 CR 버퍼를 1개 생성한 후 1번 노드로 전송합니다. 
-- 이를 통해, _db_block_max_cr_dba 파라미터는 CR 버퍼의 생성과 관련된 것이 아니라
-- CR 버퍼의 적재 개수와 관련된 것임을 알 수 있습니다.

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  gc cr block busy                   1
               [STAT]   gc cr blocks received              1
                        session logical reads              1
      2 [LMS]  [STAT]   CR blocks created                  1
                        gc cr blocks flushed               1
                        gc cr blocks served                1
                        session logical reads              3

-- 버퍼 캐시내의 큰 변화는 없습니다. 즉, 여전히 CR 버퍼의 개수는 6개입니다.
-- 다만, 새로운 CR 버퍼가 1개 적재되었고 기존의 CR 버퍼 1개는 aged out 되었음을 알 수 있습니다. 			
			
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F80728A21E8      1 CR     00                        1 0000000074034000
     00007F8072A48158      1 CR     00                        1 0000000074274000
     00007F8072A482F8      1 CR     00                        1 0000000074CD0000
     00007F8072A48478      1 CR     00                        1 00000000739E8000
     00007F8072A485F8      1 CR     00                        1 0000000074298000
     00007F8072A48778      1 CR     00                        1 0000000073D70000

OOW2 00007F79DD4C4788      1 XCUR   00000000733E2EB0          2 000000007513A000
     00007F79DD4C4908      1 CR     00                        0 0000000072EB4000
     00007F79DD4C4A88      1 CR     00                        0 0000000075038000
     00007F79DD4C4C08      1 CR     00                        0 00000000734C2000
     00007F79DD4C4D88      1 CR     00                        0 0000000073194000
     00007F79DD4C4F08      1 CR     00                        0 000000007545E000
     00007F79DD4C5088      1 CR     00                        0 0000000075772000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000733E2F38      1 KJUSEREX  GRANTED    00000000733E2EB0      1 XCUR
OOW3 00000000696D70C8      1 KJUSEREX  GRANTED

3번 노드에서 동일한 테스트를 수행한 결과, GCS SHADOW가 생성되지 않다는 점을 제외하면 1번 노드의 테스트 결과와 동일합니다. 따라서 설명은 생략합니다. 


이전: [캐시 퓨전 #1] SELECT 시에 발생하는 gc cr grant 2-way 대기이벤트에 대한 이해
다음: [캐시 퓨전 #3] 커밋된 블록 SELECT 시에 발생하는 gc cr/current block 2-way, 3-way 대기이벤트 및 _fairness_threshold 파라미터에 대한 이해



 

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

이번 시간에 살펴볼 내용은 캐시 퓨전 시에 발생하는 클러스터 관련 대기이벤트들 및 이와 연관된 성능 지표들의 변경사항, 그리고 버퍼 캐시 내의 버퍼 상태 및 GRD의 변경 사항들입니다. 테스트를 위해 10046 트레이스, V$SESSTAT, X$BH, X$KJBL Fixed 테이블을 이용했습니다. 연재 순서는 다음과 같습니다.


[캐시 퓨전 #1] SELECT 시에 발생하는 gc cr grant 2-way 대기이벤트에 대한 이해


테스트 환경 : Oracle 12.1.0.2 (64bits) 3 노드 RAC


1. 테스트 개요


2번 노드에서 레코드 1건 (마스터노드: 3번)을 조회한 후에 1번 및 3번 노드에서 동일 레코드를 각각 조회합니다. 테스트의 편의성을 위해 인덱스를 생성하지 않고 해당 레코드의 ROWID를 이용해서 조회하며, 조회 시에 발생하는 대기이벤트와 성능지표를 살펴보고 버퍼 캐시 및 GRD의 변경 내용을 확인합니다.



2. 초기 환경 SETUP


-- 테스트 테이블 생성 및 데이터 입력

SCOTT@OOW1:1> drop table t1 purge;
SCOTT@OOW1:1> create table t1 (c1 number, c2 number);
SCOTT@OOW1:1> insert into t1 select level, level from dual connect by level<=10000;
SCOTT@OOW1:1> commit;
SCOTT@OOW1:1> exec dbms_stats.gather_table_stats(user,'T1');

--C1=1에 대한 블록 마스터 노드가 OOW3 (KJBRMASTER=2)임을 확인

SCOTT@OOW1:1> @fnd_blk_master T1 1

        C1     OBJ_NO    FILE_NO     BLK_NO
---------- ---------- ---------- ----------
         1      93823          6        228

       X$BH X$KJBR                                                       X$KJBR
INST  CLASS NAME                           KJBLNAME2       KJBRGRANT     MASTER
---- ------ ------------------------------ --------------- --------- ----------
OOW3      1 [0xe4][0x6],[BL][ext 0x0,0x0]  228,6,BL        KJUSEREX           2

-- 모든 노드에서 buffer cache flush 수행 

SYS@OOW1:1> alter system flush buffer_cache;
SYS@OOW2:2> alter system flush buffer_cache;
SYS@OOW3:3> alter system flush buffer_cache;



3. 2번 노드에서 1건 조회


2번 노드에서 1건을 조회하면 해당 블록에 대한 SCUR 버퍼가 버퍼 캐시에 적재됩니다. (그림-1 참조) 이때 발생하는 변경 사항은 아래의 테스트 결과 중간중간에 주석으로 설명해 두었습니다.


그림-1. 2번 노드에서 1건 조회 후의 버퍼 캐시 변경 내용


-- 해당 블록은 로컬 및 리모트 버퍼 캐시에 존재하지 않으므로 3번 노드의 LMS로부터 블록 액세스 권한을 부여 받습니다. 
-- 이로 인해 'gc cr grant 2-way' 대기이벤트가 1회 발생합니다. 
-- 그런 후에, 싱글 블록 IO를 이용해서 해당 블록(File#=6, Block#=228)을 메모리로 적재합니다. 
-- 이때 'db file sequential read' 대기이벤트가 1회 발생합니다.
 
SCOTT@OOW2:2> @set_trace_on 10046 8
SCOTT@OOW2:2> @one_row_select 

WAIT #140225505500112: nam='gc cr grant 2-way' ela= 1991 p1=6 p2=228 p3=1 obj#=93696 tim=282496042645
WAIT #140225505500112: nam='db file sequential read' ela= 4141 file#=6 block#=228 blocks=1 obj#=93696 tim=282496046954

-- 10046 트레이스에서 확인한 것과 동일한 대기이벤트 정보를 확인할 수 있습니다. 
-- 더불어 DISK IO 1회, 메모리 IO 1회가 발생한 것을 알 수 있습니다.

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      2 [FG]   [EVENT]  db file sequential read            1
                        gc cr grant 2-way                  1
               [STAT]   physical reads                     1
                        session logical reads              1

-- 2번 노드에 SCUR 버퍼가 1개 적재되었습니다. 
-- 그리고 2번 노드의 GRD에 GCS 클라이언트 (락 엘리먼트 존재)가 1개 생성되고 
-- 마스터 노드인 3번 노드에 GCS SHADOW가 1개 생성되었습니다. 
				
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW2 00007F79DD4F7A60      1 SCUR   00000000733E2EB0          1 00000000738EC000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000733E2F38      1 KJUSERPR  GRANTED    00000000733E2EB0      1 SCUR
OOW3 00000000696EB438      1 KJUSERPR  GRANTED



4. 2번 노드에서 1번 더 조회


2번 노드에서 동일한 레코드를 1번 더 조회할 경우에는 로컬 캐시에서 해당 블록을 읽게 됩니다. 따라서 클러스터 및 IO 관련 대기이벤트 및 GRD 내의 변경은 발생하지 않습니다. 로컬 캐시에서 원하는 블록을 읽었으므로 메모리 IO가 1회 증가하고 해당 버퍼의 TCH가 2로 증가하는 정도의 변경만 발생합니다.


-- 클러스터 및 IO 관련 대기이벤트는 발생하지 않습니다.

SCOTT@OOW2:2> @set_trace_on 10046 8
SCOTT@OOW2:2> @one_row_select 

-- 해당 버퍼에 대한 메모리 IO가 1회 발생합니다. 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      2 [FG]   [STAT]   session logical reads              1

-- 해당 버퍼에 대한 액세스로 인해 TCH가 2로 증가합니다.
	  
SYS@OOW1:1> @fnd_gcs_detail 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW2 00007F79DD4FAC58      1 SCUR   00000000733E2EB0          2 0000000073922000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW2 00000000733E2F38      1 KJUSERPR  GRANTED    00000000733E2EB0      1 SCUR
OOW3 00000000696D44B8      1 KJUSERPR  GRANTED

5. 1번 노드에서 조회


1번 노드에서 동일한 레코드를 조회하면 해당 블록에 대한 SCUR 버퍼가 버퍼 캐시에 적재됩니다. (그림-2 참조) 캐시 퓨전을 설명한 문서들을 보면 이러한 경우에는 해당 블록은 캐시 퓨전을 통해서 리모트 캐시(2번 노드)에서 전송 받고, 이로 인해 'gc current block 2/3 way' 대기이벤트가 발생하는 것으로 되어있습니다만, 테스트 결과는 조금 다릅니다. 이러한 차이는 테스트 환경 (버전 또는 buffer cache flush 여부 등)의 차이라고 보여집니다.


그림-2. 1번 노드에서 1건 조회 후의 버퍼 캐시 변경 내용


-- 2번 노드와 동일한 결과를 나타냅니다. 

SCOTT@OOW1:1> @set_trace_on 10046 8
SCOTT@OOW1:1> @one_row_select 

WAIT #139902827437888: nam='gc cr grant 2-way' ela= 4187 p1=6 p2=228 p3=1 obj#=93696 tim=309078519225
WAIT #139902827437888: nam='db file sequential read' ela= 6589 file#=6 block#=228 blocks=1 obj#=93696 tim=309078528563

-- V$SESSTAT 뷰의 변경 사항 (참고만 하세요) 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      1 [FG]   [EVENT]  db file sequential read            1
                        gc cr grant 2-way                  1
               [STAT]   physical reads                     1
                        session logical reads              1

-- 1번 노드에 SCUR 버퍼가 1개 적재되었습니다. 
-- 그리고 2번 노드의 GRD에 GCS 클라이언트가 1개 생성되고, 
-- 마스터 노드인 3번 노드에 GCS SHADOW가 1개 생성되었습니다.
 						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F80726712D0      1 SCUR   00000000747F19D8          1 00000000750EE000
OOW2 00007F79E2242F58      1 SCUR   00000000733E2EB0          0 0000000074940000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 00000000747F1A60      0 KJUSERPR  GRANTED    00000000747F19D8      1 SCUR
OOW2 00000000733E2F38      1 KJUSERPR  GRANTED    00000000733E2EB0      1 SCUR
OOW3 00000000697216F0      1 KJUSERPR  GRANTED
OOW3 00000000696CDD20      0 KJUSERPR  GRANTED


6. 3번 노드에서 조회


3번 노드에서 동일한 레코드를 조회하면 해당 블록에 대한 SCUR 버퍼가 버퍼 캐시에 적재됩니다. (그림-3 참조)


그림-3. 3번 노드에서 1건 조회 후의 버퍼 캐시 변경 내용


-- 3번 노드가 마스터 노드이므로 GRANT 수행 없이 싱글 블록 IO를 이용해서 버퍼에 적재합니다.
-- 따라서 'gc cr grant 2-way' 대기 없이 'db file sequential' 대기이벤트만 1회 발생합니다.

SCOTT@OOW3:3> @set_trace_on 10046 8
SCOTT@OOW3:3> @one_row_select 

WAIT #140357040867896: nam='db file sequential read' ela= 4382 file#=6 block#=228 blocks=1 obj#=93696 tim=282758433936

-- V$SESSTAT 뷰의 변경 사항 (참고만 하세요) 

SYS@OOW1:1> @init_temp_sesstat 91 65 43
SYS@OOW1:1> @get_temp_sesstat  91 65 43

INST_ID SERVER FLAG     NAME                           VALUE
------- ------ -------- ------------------------------ -----
      3 [FG]   [EVENT]  db file sequential read            1
               [STAT]   physical reads                     1
                        session logical reads              1						

-- 3번 노드에 SCUR 버퍼가 1개 적재되었습니다. 
-- 3번 노드가 마스터 노드이므로 GCS SHADOW는 생성되지 않고 GCS 클라이언트만 1개 생성되었습니다. 
						
SYS@OOW1:1> @fnd_gcs_detail2 6 228

                        X$BH X$BH   X$BH                   X$BH
INST ADDR              CLASS STATE  LE_ADDR                 TCH BA
---- ---------------- ------ ------ ---------------- ---------- ----------------
OOW1 00007F8072671870      1 SCUR   00000000747F19D8          1 0000000075744000
OOW2 00007F79DD4C9298      1 SCUR   00000000733E2EB0          1 0000000073418000
OOW3 00007FBB31F831B0      1 SCUR   00000000757DC498          1 0000000072E32000

     X$KJBL           X$KJBL X$KJBL    X$KJBL     X$BH               X$BH X$BH
INST LOCKP             OWNER GRANT     LOCKST     LE_ADDR           CLASS STATE
---- ---------------- ------ --------- ---------- ---------------- ------ ------
OOW1 00000000747F1A60      0 KJUSERPR  GRANTED    00000000747F19D8      1 SCUR
OOW2 00000000733E2F38      1 KJUSERPR  GRANTED    00000000733E2EB0      1 SCUR
OOW3 0000000069715DC8      1 KJUSERPR  GRANTED
OOW3 00000000697273C0      0 KJUSERPR  GRANTED
OOW3 00000000757DC520      2 KJUSERPR  GRANTED    00000000757DC498      1 SCUR


다음: [캐시 퓨전 #2] 변경중인 블록 SELECT 시에 발생하는 gc cr block busy 대기이벤트 및 _db_block_max_cr_dba 파라미터에 대한 이해

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

GCS (Glocal Cache Service)와 관련된 인터널 문서를 읽다보면 GCS SHADOW란 용어를 접하게 됩니다. 하지만 GCS SHADOW의 명확한 동작원리에 대해서 언급한 문서를 찾기가 힘듭니다. 그나마 Juian Dyke의 2008년도 PDF 문서에 다음과 같은 정의와 구성도를 확인할 수 있습니다.


"GCS Shadow describes blocks held by other instances, but mastered locally" [Julian Dyke]


그림-1. GCS 메모리 구성도 (참조문헌: Julian Dyke PDF)


즉, GCS SHADOW란 마스터에 속한 블록을 다른 노드에서 사용할때 이를 표현하는 구조체입니다. (설명이 조금 어렵죠?) 그리고 "그림-1"에서 보여지는 것처럼 GCS SHADOW는 락 엘리먼트를 가지고 있지 않습니다. 그런데 이 설명과 그림만으로는 GCS SHADOW를 정확히 이해하기는 어렵습니다. (적어도 저의 경우는 그랬습니다) 그렇다면 GCS SHADOW는 어떻게 동작하고 어떤 목적으로 사용될까요? 이를 분석하기 위해 테스트를 진행한 결과를 다음과 같이 정리합니다.



1. GCS SHADOW의 동작 원리 및 목적


1-1. GCS SHADOW의 동작 원리

  1. 마스터 노드에서 해당 블록을 액세스할 경우에는 GCS CLIENT가 1개 생성되고 GCS SHADOW는 생성되지 않습니다.
  2. 리모트 노드에서 해당 블록을 액세스할 경우에는 리모트 노드에 GCS CLIENT가 1개 생성되고, 마스터 노드에는 이와 관련된 GCS SHADOW가 1개 생성됩니다. 여러 개의 리모트 노드에서 해당 블록을 액세스한다면 리모트 노드 개수만큼의 GCS SHADOW가 마스터 노드에 생성됩니다.
Note
설명의 편의성을 위해 GCS CLIENT와 GCS SHADOW로 나누었으나, 오라클 내부적으로는 모두 GCS SHADOW로 관리됩니다. GCS CLIENT는 락 엘리먼트가 있는 GCS 구조체 (X$KJBL내에 생성됨)이고 GCS SHADOW는 락 엘리먼트가 없는 GCS 구조체라고 이해하시면 좋습니다. 개인적인 생각이지만 오라클은 용어 및 약어 선정을 아주 잘하는 회사인것 같습니다. GCS SHADOW란 용어도 알고 보면 아주 적절한 용어라고 보입니다. 즉, 그림자와 같이 형체(X$KJBL 구조체)는 동일하지만 알맹이(락 엘리먼트)는 없는 것을 잘 표현하고 있습니다.


그런데 여기서 의문점이 하나 생기게됩니다. "오라클은 이러한 중복 관리를 부하를 감수하면서도 GCS SHADOW를 사용할까?"라는 것이죠. 예를 들어, 마스터 노드의 블록들을 리모트 노드에서 대량으로 액세스하게 되면, 마스터 노드에는 블록 개수만큼의 GCS SHADOW 구조체를 shared pool의 gcs shadow 영역에 생성해야하는 부하가 발생하게 됩니다. 이와 같은 오퍼레이션은 CPU 및 shared pool 사용 측면에서 모두 부하를 유발하게 됩니다. 그렇다면 왜 필요한걸까요?


1-2. GCS SHADOW의 목적
테스트를 통해 추론된 결론은 "GCS SHADOW의 목적은 마스터 노드에 속한 블록들의 사용 노드를 확인하기 위한 것"입니다. 그림-2~그림-4를 보시면 쉽게 이해될것 같습니다.


그림-2. 초기 상태


그림-3. RAC3 노드에서 UPDATE 수행  


그림-4. RAC2번 노드에서 SELECT 수행

Note
해당 블록의 마스터 노드는 OOW1이므로 OOW1의 GCS 리소스 구조체를 접근한 후, 해당 구조에 아래 딸린 GCS CLIENT/SHADOW 구조체를 확인합니다. 확인 결과, GCS SHADOW의 정보를 통해 해당 블록은 현재 3번 노드에 있다는 사실을 알 수 있습니다. 이와 같이 GCS SHADOW는 마스터 블록의 사용 노드를 확인하기 위한 용도로 사용된다고 할 수 있습니다. 


이러한 결론을 이끌어냈던 테스트 방법에 대해서 자세히 살펴보도록 하겠습니다.



2. GCS SHADOW의 동작원리 분석을 위한 테스트 내역


2-1. 테스트 데이터 생성

SCOTT @ OOW1 > drop table t1 purge;
SCOTT @ OOW1 > create table t1 (c1 number, dummy char(10));
SCOTT @ OOW1 > insert into t1 select level, level from dual connect by level<=10000;
SCOTT @ OOW1 > commit;
SCOTT @ OOW1 > create index t1_idx01 on t1(c1) nologging;
SCOTT @ OOW1 > exec dbms_stats.gather_table_stats(user,'T1');


2-2. 초기 상태 확인

-- 레코드 1건 조회

SCOTT @ OOW1 > select /*+ index(t1 t1_idx01) */
       count(*),
       max(dbms_rowid.rowid_relative_fno(rowid)) file_no,
       max(dbms_rowid.rowid_block_number(rowid)) blk_no
from   t1
where  c1=1
and    dummy <> '9999';

-- 해당 레코드가 속한 블록의 마스터 노드 확인 (마스터 노드가 0번 즉, OOW1번 노드임을 확인)

SCOTT @ OOW1 > @fnd_blk_master T1 1

        C1     OBJ_NO    FILE_NO     BLK_NO
---------- ---------- ---------- ----------
         1      93240          8        134

INST      CLASS KJBRNAME                       KJBLNAME2       KJBRGRANT KJBRMASTER
---- ---------- ------------------------------ --------------- --------- ----------
OOW1          1 [0x86][0x8],[BL][ext 0x0,0x0]  134,8,BL        KJUSEREX           0


2-3. OOW3 노드에서 UPDATE 수행 후의 변경 사항 확인

-- 테스트의 편의성을 위해 모든 노드에서 alter system flush buffer cache 수행 후 3번 노드에서 update 수행

SCOTT @ OOW3 > update  t1 set c1=-1 where c1=1;

-- 결과 확인
 
SCOTT @ OOW1 > @fnd_gcs_detail 8 134

                            X$BH X$BH       X$BH                   X$BH
INST ADDR                  CLASS STATE      LE_ADDR                 TCH
---- ---------------- ---------- ---------- ---------------- ----------
OOW3 00007F37A4573068          1 XCUR       0000000072FF5948          1

     X$KJBR               X$KJBR X$KJBR
INST RESP                 MASTER NAME
---- ---------------- ---------- ------------------------------
OOW1 000000006946A358          0 [0x86][0x8],[BL][ext 0x0,0x0]

     X$KJBL               X$KJBL X$KJBL    X$KJBL     X$BH                   X$BH X$BH
INST LOCKP                 OWNER GRANT     LOCKST     LE_ADDR               CLASS STATE
---- ---------------- ---------- --------- ---------- ---------------- ---------- ----------
OOW1 0000000069722CF8          2 KJUSEREX  GRANTED
OOW3 0000000072FF59D0          2 KJUSEREX  GRANTED    0000000072FF5948          1 XCUR


결과분석
1. 3번 노드에 XCUR 버퍼 1개 할당
2. 해당 블록의 마스터 노드는 0번 (즉, OOW1)임을 재확인
3. 3번 노드에 GCS CLIENT 1개 생성. 그리고 1번 노드에 GCS SHADOW 1개 생성됨


2-4. OOW2 노드에서 SELECT 수행 후의 변경 사항 확인

-- 2번 노드에서 SELECT 수행 

SCOTT @ OOW2 > select * from t1 where c1=2;

-- 결과 확인
 
SCOTT @ OOW1 > @fnd_gcs_detail 8 134

                            X$BH X$BH       X$BH                   X$BH
INST ADDR                  CLASS STATE      LE_ADDR                 TCH
---- ---------------- ---------- ---------- ---------------- ----------
OOW2 00007F6A25D42AD8          1 CR         00                        1

OOW3 00007F37A4572EE8          1 XCUR       0000000072FF5948          1
     00007F37A4573068          1 CR         00                        0

     X$KJBR               X$KJBR X$KJBR
INST RESP                 MASTER NAME
---- ---------------- ---------- ------------------------------
OOW1 000000006946A358          0 [0x86][0x8],[BL][ext 0x0,0x0]

     X$KJBL               X$KJBL X$KJBL    X$KJBL     X$BH                   X$BH X$BH
INST LOCKP                 OWNER GRANT     LOCKST     LE_ADDR               CLASS STATE
---- ---------------- ---------- --------- ---------- ---------------- ---------- ----------
OOW1 0000000069722CF8          2 KJUSEREX  GRANTED
OOW3 0000000072FF59D0          2 KJUSEREX  GRANTED    0000000072FF5948          1 XCUR


결과분석
1. 3번 노드의 XCUR 버퍼를 1개 복사해서 새로운 XCUR 버퍼 할당. 기존 XCUR 버퍼는 CR 버퍼로 락 다운그레이드됨 (ADDR로 확인)
2. 2번 노드에 CR 버퍼 복사 (3번 노드의 CR 버퍼를 전송받음)
3. CR 버퍼에 대해서는 락 엘리먼트 및 GCS CLIENT 및 SHADOW를 생성하지 않는 것을 확인


스크립트


이 글에 사용된 스크립트는 다음과 같습니다.

fnd_blk_master 
fnd_gcs_detail


글을 마치며


설명을 단순화하기 위해서 테스트의 예제를 UPDATE로 했지만, SELECT 및 UPDATE등 다양한 테스트를 한 후 fnd_gcs_detail 스크립트를 이용해서 결과를 분석해보시면 RAC 내부 동작원리를 좀 더 파악할 수 있으리라 생각됩니다. 그리고 이번 포스팅을 끝으로 3개월 동안 진행한 "RAC 동작원리에 대한 연재"를 마무리하려고 합니다. GCS, GES 및 RAC 관련 파라미터에 대한 설명은 연재 내에서 다루기보다는 "성능 분석"이라는 새로운 주제 내에서 다룰 예정입니다. 지금까지는 다소 지루한 개론 부분이었다면 앞으로는 실용적인 측면을 가미한 내용으로 찾아뵙도록 하겠습니다.  


저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

일반적으로 노드 별로 스키마를 분리해서 운영하는 환경 (또는 인스턴스별로 업무가 나뉜 환경)에서는 블록 마스터 노드가 분산되더라도 성능 상의 문제는 거의 없습니다. (여기서 "거의"라고 하는 부분은 초기 디스크 IO시에 GC GRANT 메시지를 전송 받는데 필요한 몇 밀리세컨 정도의 미미한 부하) 즉, 초기 1회의 디스크 IO를 제외하면, 이후의 메모리 IO는 모두 로컬 노드에서 수행되므로 성능 이슈는 없다고 할 수 있습니다. 하지만, 아주 운이 없는 경우, 초기 1회의 디스크 IO를 위해 GC GRANT 메세지를 전송 받는 시점에(해당 블록의 마스터 노드가 리모트인 경우), 리모트 노드의 LMS의 부하로 인해 메시지 전송이 지연된다면 gc cr grant 2-way  대기이벤트의 대기 시간이 길어지는 문제가 발생하며, 이로 인해 장애가 유발될 가능성도 배제할 수 없습니다. 이번 시간에는 이러한 문제 가능성에 대해서 테스트를 통해 검증해보고, 수동 DRM을 통해 문제를 해결하는 방안을 설명합니다.


1) 1개 로우의 마스터 노드 확인


테스트를 위해 1개 로우가 저장된 블록의 마스터 노드를 확인합니다. 확인 결과, C1=129 로우의 마스터 노드는 OOW2임을 알 수 있습니다. (참고로 KJMRMASTER 칼럼 값은 0부터 시작합니다. 따라서 1인 경우에는 2번 노드인 OOW2가 마스터 노드가 됩니다)

SCOTT @ OOW1 >  @fnd_blk_master T1 129

        C1     OBJ_NO    FILE_NO     BLK_NO
---------- ---------- ---------- ----------
       129      93205          8        275


INST      CLASS KJBRNAME                       KJBLNAME2       KJBRGRANT KJBRMASTER
---- ---------- ------------------------------ --------------- --------- ----------
OOW2          1 [0x113][0x8],[BL][ext 0x0,0x0] 275,8,BL        KJUSEREX           1



2) 10046 트레이스를 이용한 대기 이벤트 분석


인덱스 및 테이블 블록에 대한 마스터가 모두 리모트 노드이므로 db file sequential read 대기이벤트가 발생하기 전에 gc cr grant 2-way 대기이벤트가 발생하는 것을 확인할 수 있습니다. (대기이벤트에 대한 자세한 설명은 별도 포스팅으로 다룰 예정입니다) 개별 gc cr grant 2-way 대기이벤트의 대기시간은 1~2 밀리세컨 이하이므로 성능 상의 문제는 없다고 볼 수 있습니다. 다만, 디스크 IO가 빈번하게 발생하는 경우에는 그와 비례해서 대기 시간이 증가한다는 점은 간과해서는 안됩니다. 이런 경우에는 4) 항목을 참고해서 수동 리마스터링을 고려할 필요가 있습니다.

SCOTT @ OOW1 > alter system flush buffer_cache;
SCOTT @ OOW1 > @set_trace_on 10046 8
SCOTT @ OOW1 > select /*+ index(t1 t1_idx01) */ c1, dummy from t1 where c1=129;
 
-- 인덱스 블록 관련 gc 이벤트 2개 발생
WAIT #139730535523040: nam='gc cr grant 2-way' ela= 934 p1=9 p2=131 p3=1 obj#=93206 tim=92098682472
WAIT #139730535523040: nam='db file sequential read' ela= 1657 file#=9 block#=131 blocks=1 obj#=93206 tim=92098684434
WAIT #139730535523040: nam='gc cr grant 2-way' ela= 814 p1=9 p2=177 p3=1 obj#=93206 tim=92098689422
WAIT #139730535523040: nam='db file sequential read' ela= 1209 file#=9 block#=177 blocks=1 obj#=93206 tim=92098691801
-- 테이블 블록 관련 gc 이벤트 1개 발생
WAIT #139730535523040: nam='gc cr grant 2-way' ela= 1238 p1=8 p2=275 p3=1 obj#=93205 tim=92098694278
WAIT #139730535523040: nam='db file sequential read' ela= 1420 file#=8 block#=275 blocks=1 obj#=93205 tim=92098698115



3) LMS Hang 유발 후 동작 방식 확인


블록 마스터 노드인 OOW2 노드의 LMS를 Hang 상태로 만들면 OOW1번에서 해당 블록을 요청하는 세션 역시 Hang 상태에 빠지게 됩니다. (Kill 명령어로 LMS를 stop 시키는 것은 테스트 목적으로 수행한 것이므로 운영 장비에서는 절대 수행해서는 안됩니다. 참고로, 수십 초 이상 LMS를 stop 시킬 경우 인스턴스가 Down되므로 테스트 시에 참고하기 바랍니다) 테스트의 편의성을 위해서 LMS을 stop 시켰으나, 이와 유사하게 리모트 노드의 LMS가 매우 바쁜 상황에서도 이러한 지연이 발생할 가능성이 있다고 이해하시면 좋을 것 같습니다.

-- LMS Hang 유발
SCOTT @ OOW2 > host ps -ef | grep lms | grep OOW2 | grep -v grep
oracle    2330     1  0 20:39 ?        00:01:08 ora_lms0_OOW2
SCOTT @ OOW2 > host kill -stop 2330


-- Hang 유발 후 1번 노드에서 조회
SCOTT @ OOW1 > select /*+ index(t1 t1_idx01) */ c1, dummy from t1 where c1=129;


-- 대략 10초 이후 LMS Hang 해제
SCOTT @ OOW2 > host kill -cont 2330


-- 1번 노드 세션의 상태 분석 (gc cr grant 2-way 대기이벤트의 대기시간이 10초 이상 소요됨)
WAIT #139730535523040: nam='gc cr grant 2-way' ela= 11144860 p1=9 p2=131 p3=1 obj#=93206 tim=92297618736
WAIT #139730535523040: nam='db file sequential read' ela= 1621 file#=9 block#=131 blocks=1 obj#=93206 tim=92297620594
WAIT #139730535523040: nam='gc cr grant 2-way' ela= 2555 p1=9 p2=177 p3=1 obj#=93206 tim=92297624002
WAIT #139730535523040: nam='db file sequential read' ela= 2293 file#=9 block#=177 blocks=1 obj#=93206 tim=92297626538
WAIT #139730535523040: nam='gc cr grant 2-way' ela= 2075 p1=8 p2=275 p3=1 obj#=93205 tim=92297629261
WAIT #139730535523040: nam='db file sequential read' ela= 2188 file#=8 block#=275 blocks=1 obj#=93205 tim=92297631913



4) 수동 리소스 리마스터링을 이용한 gc cr grant 2-way 대기이벤트 제거 방법


노드 별로 스키마를 분리했거나, 노드 별로 작업이 분리된 경우에는 수동 리소스 리마스터링을 이용해서 gc cr grant 2-way 대기이벤트를 제거하는 것이 가능합니다. 아래 내용을 참고하세요.

-- 테이블스페이스 번호 확인
SYS @ OOW1 > select ts#, name from ts$ where name in ('TEST_TS','TEST_IDX01');

       TS# NAME
---------- ------------------------------
         9 TEST_IDX01
         8 TEST_TS


-- 오브젝트 번호 확인
SYS @ OOW1 > select data_object_id, object_name from dba_objects where owner='SCOTT' and object_name like 'T1%';

DATA_OBJECT_ID OBJECT_NAME
-------------- ----------------
         93206 T1_IDX01
         93205 T1


-- oradebug로 수동 리마스터링 수행
SYS @ OOW1 > oradebug setmypid
SYS @ OOW1 > oradebug lkdebug -m pkey 93205 8
SYS @ OOW1 > oradebug lkdebug -m pkey 93206 9


-- 모든 노드에서 flush 수행
SYS @ OOW1 > alter system flush buffer_cache;
SYS @ OOW2 > alter system flush buffer_cache;
SYS @ OOW3 > alter system flush buffer_cache;


SCOTT @ OOW1 > select /*+ index(t1 t1_idx01) */ c1, dummy from t1 where c1=129;

-- gc cr grant 2-way 대기이벤트가 사라진 것을 확인
WAIT #139792444535272: nam='db file sequential read' ela= 9540 file#=9 block#=131 blocks=1 obj#=93206 tim=96291049226
WAIT #139792444535272: nam='db file sequential read' ela= 1279 file#=9 block#=177 blocks=1 obj#=93206 tim=96291050759
WAIT #139792444535272: nam='db file sequential read' ela= 1385 file#=8 block#=275 blocks=1 obj#=93205 tim=96291052617


이와 같이, 수동 리마스터링을 통해서 GC 관련 대기이벤트를 튜닝하는 방법이 가능합니다. 하지만 _gc_affniti_time (또는 _gc_policy_time)을 0으로 설정해서 DRM을 disable한 경우에는 수동 리마스터링이 수행되지 않는다고 합니다. 따라서, _gc_affniti_time을 0으로 설정하기보다는 _gc_affnity_minimum (또는 _gc_policy_minimum) 값을 아주 높은 값 (수백만)으로 설정해서 DRM은 발생하지 않도록 한 후, 적절히 수동 DRM을 통해 GC 대기이벤트를 튜닝하는 것도 고려해 볼만한 방법입니다.


[20] GCS SHADOW 동작 원리 및 GCS SHADOW의 필요성에 대한 설명 바로가기

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

이번 시간에는 블록 마스터 해싱과 관련된 내용을 살펴보도록 하겠습니다. 일반적으로 오라클은 연속된 블록 단위로 동일한 마스터 노드를 할당하며, 연속된 블록의 단위는 _lm_contiguous_res_count 파라미터 설정 값에 따라 결정된다고 알려져 있습니다. 테스트를 통해 확인해보도록 하겠습니다.



1) _lm_contiguous_res_count 파라미터 설정값 확인


SYS @ OOW1 > @get_param _lm_contigu

NAME                       VALUE      DEFLT      DESCRIPTION
-------------------------- ---------- ---------- --------------------------------------------------
_lm_contiguous_res_count   128        TRUE       number of contiguous blocks that will hash to the
                                                 same HV bucket


Note
파라미터 설정 값은 128임을 확인했습니다



2) 테스트용 테이블 스페이스 생성


테스트 결과를 쉽게 확인하기 위해서 테이블 및 인덱스 별로 별도의 테이블스페이스를 생성합니다.

create tablespace TEST_TS    datafile '+DATA' size 500m;
create tablespace TEST_IDX01 datafile '+DATA' size 500m;



3) 테스트용 테이블 생성


테스트의 편의성을 위해서 블록 당 1개의 레코드만 저장되도록 합니다. 그리고 Dynamic Sampling으로 인한 GC 통신 발생 현상을 제거하기 위해서 T1 테이블에 통계 정보를 생성합니다.

SCOTT @ OOW1 > create table t1 (c1 number, c2 char(2000), dummy char(2000)) pctfree 90 tablespace test_ts;
SCOTT @ OOW1 > insert into t1 select level, level, level from dual connect by level <= 2000;
SCOTT @ OOW1 > commit;

SCOTT @ OOW1 > exec dbms_stats.gather_table_stats(user,'T1');

SCOTT @ OOW1 > select count(*) row_cnt,
       count(distinct dbms_rowid.rowid_block_number(rowid)) blk_cnt,
       min(dbms_rowid.rowid_block_number(rowid)) min_dba,
       max(dbms_rowid.rowid_block_number(rowid)) max_dba
       from   t1;

   ROW_CNT    BLK_CNT    MIN_DBA    MAX_DBA
---------- ---------- ---------- ----------
      2000       2000        131       2175


4) 테이블 블록 마스터 노드 확인


블록 마스터 노드를 확인하는 스크립트는 내부적으로 GX$ 뷰를 이용합니다. GX$ 뷰를 생성하는 방법은 "여기"를 참고하시기 바랍니다.

SCOTT @ OOW1 > @fnd_obj_master T1

   

    INST      CLASS KJBRNAME                       KJBLNAME2       KJBRGRANT KJBRMASTER
    ---- ---------- ------------------------------ --------------- --------- ----------
   1 OOW3          8 [0x80][0x8],[BL][ext 0x0,0x0]  128,8,BL       KJUSEREX           2
   2 OOW3          9 [0x81][0x8],[BL][ext 0x0,0x0]  129,8,BL       KJUSEREX           2
   3 OOW3          4 [0x82][0x8],[BL][ext 0x0,0x0]  130,8,BL       KJUSEREX           2
... 생략
 128 OOW3          1 [0xff][0x8],[BL][ext 0x0,0x0]  255,8,BL       KJUSEREX           2
---------------------------------------------------------------------------------------
 129 OOW1          8 [0x100][0x8],[BL][ext 0x0,0x0] 256,8,BL       KJUSEREX           0
 130 OOW1          8 [0x101][0x8],[BL][ext 0x0,0x0] 257,8,BL       KJUSEREX           0
 131 OOW1          1 [0x102][0x8],[BL][ext 0x0,0x0] 258,8,BL       KJUSEREX           0
... 생략
 256 OOW1          1 [0x17f][0x8],[BL][ext 0x0,0x0] 383,8,BL       KJUSEREX           0
---------------------------------------------------------------------------------------
 257 OOW2          8 [0x180][0x8],[BL][ext 0x0,0x0] 384,8,BL       KJUSEREX           1
 258 OOW2          8 [0x181][0x8],[BL][ext 0x0,0x0] 385,8,BL       KJUSEREX           1
 259 OOW2          1 [0x182][0x8],[BL][ext 0x0,0x0] 386,8,BL       KJUSEREX           1
... 생략
 384 OOW2          1 [0x1ff][0x8],[BL][ext 0x0,0x0] 511,8,BL       KJUSEREX           1
---------------------------------------------------------------------------------------
 385 OOW3          8 [0x200][0x8],[BL][ext 0x0,0x0] 512,8,BL       KJUSEREX           2
 386 OOW3          8 [0x201][0x8],[BL][ext 0x0,0x0] 513,8,BL       KJUSEREX           2
 387 OOW3          1 [0x202][0x8],[BL][ext 0x0,0x0] 514,8,BL       KJUSEREX           2
... 생략


결과분석
위의 결과에서 보는 것과 같이 _lm_contiguous_res_count 파라미터의 설정 값인 128개 단위로 마스터 노드를 할당하는 것을 알 수 있습니다. 다만, 예상했던 것과는 달리 1->2->3->1-2->3.. 식의 순차적인 할당 방식은 아닙니다 (2->0->1->2->1->0->2->0->1->2.. 식으로 마스터 노드를 할당)



5) 인덱스 블록 마스터 노드 확인


인덱스도 테이블과 동일한 방식으로 마스터 노드를 할당하는지여부를 확인합니다. 버퍼 캐시가 작은 환경에서는 스크립트 수행 전에 인덱스를 full scan하는 SQL을 수행해서 인덱스 블록들을 버퍼 캐시로 로딩하는 것이 좋습니다.

SCOTT @ OOW1 > create index t1_idx01 on t1 (c1, c2) tablespace test_idx01 nologging;
SCOTT @ OOW1 > select /*+ index (t1 t1_idx01) */ count(*) from t1 where c1>0;

  COUNT(*)
----------
      2000


SCOTT @ OOW1 > @fnd_obj_master T1_IDX01


    INST      CLASS KJBRNAME                       KJBLNAME2       KJBRGRANT KJBRMASTER
    ---- ---------- ------------------------------ --------------- --------- ----------
  1 OOW1          8 [0x80][0x9],[BL][ext 0x0,0x0]  128,9,BL        KJUSEREX           0
  2 OOW1          9 [0x81][0x9],[BL][ext 0x0,0x0]  129,9,BL        KJUSEREX           0
  3 OOW1          4 [0x82][0x9],[BL][ext 0x0,0x0]  130,9,BL        KJUSEREX           0
... 생략
128 OOW1          1 [0xff][0x9],[BL][ext 0x0,0x0]  255,9,BL        KJUSERPR           0
---------------------------------------------------------------------------------------
129 OOW2          8 [0x100][0x9],[BL][ext 0x0,0x0] 256,9,BL        KJUSEREX           1
130 OOW2          8 [0x101][0x9],[BL][ext 0x0,0x0] 257,9,BL        KJUSEREX           1
131 OOW2          1 [0x102][0x9],[BL][ext 0x0,0x0] 258,9,BL        KJUSERPR           1
... 생략
256 OOW2          1 [0x17f][0x9],[BL][ext 0x0,0x0] 383,9,BL        KJUSERPR           1
---------------------------------------------------------------------------------------
257 OOW3          8 [0x180][0x9],[BL][ext 0x0,0x0] 384,9,BL        KJUSEREX           2
258 OOW3          8 [0x181][0x9],[BL][ext 0x0,0x0] 385,9,BL        KJUSEREX           2
259 OOW3          1 [0x182][0x9],[BL][ext 0x0,0x0] 386,9,BL        KJUSERPR           2
... 생략
384 OOW3          1 [0x1ff][0x9],[BL][ext 0x0,0x0] 511,9,BL        KJUSERPR           2
--------------------------------------------------------------------------------------------------------
385 OOW2          8 [0x200][0x9],[BL][ext 0x0,0x0] 512,9,BL        KJUSEREX           1
386 OOW2          8 [0x201][0x9],[BL][ext 0x0,0x0] 513,9,BL        KJUSEREX           1
387 OOW2          1 [0x202][0x9],[BL][ext 0x0,0x0] 514,9,BL        KJUSERPR           1
388 OOW2          1 [0x203][0x9],[BL][ext 0x0,0x0] 515,9,BL        KJUSERPR           1

... 생략
결과분석
인덱스 역시 테이블과 동일한 방식으로 마스터 노드를 할당하는 것을 확인할 수 있습니다. 약간의 차이는 첫번째 마스터 노드가 0(OOW1)으로 시작한다는 것이며 그 이후의 마스터 노드 순서는 테이블과 동일합니다. 이 차이점은 오브젝트 번호의 차이로 보면 될 것 같습니다.


그렇다면, 이와 같이 마스터 노드가 여러 노드로 분산되는 것이 성능 상이 문제를 유발할 수 있을까요?
해당 내용은 다음 포스팅에서 진행합니다.


[19] 블록 마스터 노드 분산에 따른 gc cr grant 2-way 문제 가능성 및 해결 방안 바로가기

저작자 표시 비영리 변경 금지
신고
크리에이티브 커먼즈 라이선스
Creative Commons License

[17] RAC GRD 개요

RAC 2016.08.02 02:58 Posted by 시연아카데미

RAC 성능 튜닝과 관련된 문서들을 보면 대부분 가장 먼저 GRD (Global Resource Directory)를 설명합니다. 아마도 RAC 성능 튜닝에 있어서 RAC의 내부 아키텍처에 대한 이해가 필수적인 요소이고, 어찌 보면 GRD가 RAC 아키텍처의 가장 중요한 부분을 차지하고 있기 때문인 것 같습니다. 대략 1주일동안 GRD에 대한 학습과 연구를 마무리하고 글을 정리하려고 보니 하나의 포스팅으로는 글이 너무 길어질 것 같아서 다음과 같이 4개의 주제로 나누어서 포스팅을 하고자 합니다.


GRD 부분부터는 내부 동작원리를 설명해야 됨에 따라 인터널한 내용을 포함하게 됩니다. 인터널 부분은 학습하는 것도 쉽지 않지만, 학습을 토대로 연구한 내용을 설명하는 것도 쉽지 않습니다. 너무 깊이 설명하면 실용성이 현저히 떨어지고, 너무 가볍게 설명하면 트러블슈팅 시에 도움이 되지 않기 때문입니다. 이러한 점을 고려해서 제가 이해하는 수준에서 적절한 깊이로 설명하려고 합니다.



들어가기에 앞서


GRD 동작원리를 연구하면서 학습한 2개의 자료를 소개합니다. RAC 인터널에 대해서 논할 때 반드시 읽어봐야 할 문서들입니다.

  • Julian Dyke의 RAC Internal PPTPDF : PPT는 2006년 자료, PDF는 2008년 자료입니다. PDF에 조금 더 설명이 보강되어 있으므로 2개의 문서를 모두 보시는것이 좋습니다. 10년전 문서이지만 RAC 인터널 관련된 대부분의 문서들의 참고 자료가 될 정도로 정리가 잘된 문서입니다. 또한, PPT 애니메이션을 이용해서 동작 원리를 너무도 명쾌하게 설명한 문서이기도 합니다.
  • Riyaj Shamsudeen의 슬라이드 노트 : Export Oracle RAC 12c의 저자인 Riyaj Shamsudeen이 작성한 문서로써 RAC와 관련된 성능 이슈를 분석할 때 반드시 읽어봐야 할 문서입니다.

이번 시간에는 몇개의 질문들을 통해 GRD에 대해서 가볍게 정리해보도록 하겠습니다.




질문-1. GRD란 무엇인가요?


GRD는 "Global 리소스 관리를 위해 사용되는 메모리 구조체"입니다. GRD가 필요한 이유는 RAC에서의 모든 리소스들은 "Global"하게 관리되어야 하기 때문입니다. GRD 내부에는 다음과 같은 2개의 리소스를 위한 구조체를 가지고 있습니다. 

  1. BL (Buffer Lock) 리소스를 위한 구조체 : 블록과 관련된 리소스를 저장하는 구조체이며 GCS (Global Cache Service)가 관리합니다. 
  2. Non-BL 리소스를 위한 구조체 : 주로 락 (TX, TM등)과 관련된 리소스를 저장하는 구조체이며 GES (Global Enqueue Service)가 관리합니다.
     



질문-2. GRD 구조체란 정확히 무엇인가요?


메모리 구조체란 C 언어의 struct라고 이해하면 됩니다. 오라클은 x$ fixed 테이블을 통해 구조체의 내용을 제공하며 GRD의 내용을 확인할 수 있는 x$ fixed 테이블은 4개입니다. (그림-1. 참조)


그림-1. GRD와 관련된 x$ fixed 테이블 및 v$ 뷰



그림-1에서 보여지는 것처럼, BL 리소스를 위한 구조체 2개 (X$KJBL, X$KJBR)와 Non-BL 리소스를 위한 구조체 2개 (X$KJILKFT, X$KJIRFT)를 제공하며, 모니터링의 편의를 위해서 "락"과 관련된 2개의 구조체 (X$KJBL, X$KJILKFT)를 UNION ALL로 묶어서 V$GES_ENQUEUE로 제공하며, "리소스"와 관련된 2개의 구조체 (X$KJBR, X$KJIRFT)를 UNION ALL로 묶어서 V$GES_RESOURCE로 제공합니다.




질문-3. 리소스와 락 구조체의 차이점은 무엇인가요?


오라클에서 리소스와 락 구조체를 분리한 이유는 리소스와 락 구조체가 1:M의 관계이기 때문입니다. 다시 말해, 리소스 구조체 내의 항목들은 "항목 별로 1개"인 반면, 락 구조체 내에는 특정 리소스에 대해서 여러 개의 항목이 저장될 수 있습니다. 예를 들어, 하나의 블록에 대한 리소스 정보는 해당 블록의 마스터 노드의 X$KJBR에만 1건 등록됩니다. 하지만 해당 블록을 모든 인스턴스에서 액세스한다면, 모든 인스턴스의 X$KBJL에는 해당 블록에 대한 락 정보가 등록되게 됩니다. 일반적으로 리소스 구조체는 리소스를 "보호"할 목적으로, 락 구조체는 리소스를 "사용"할 목적으로 이용된다고 보면 됩니다.


Note
위에 기술된 "항목 별로 1개"를 좀 더 명확히 설명하면, BL 리소스는 전 노드에 걸쳐 1개의 항목을 X$KJBR에 등록하는 반면, Non-BL 리소스는 각 노드 별로 1개의 항목을 X$KJIRFT에 등록합니다.




질문-4. GRD는 어디에, 어떻게 저장되나요?


GRD는 shared pool에 저장되며, 아래 쿼리의 결과와 같이 인스턴스 별로 균등하게 나눠서 관리합니다. GRD 전체 Set을 인스턴스마다 중복해서 관리하지 않고, 균등하게 나눠서 관리하는 이유는 SGA 메모리의 낭비를 막기 위해서 입니다. 만일 모든 모드가 GRD의 전체 Set을 저장한다면 노드가 증가할수록 메모리 사용 측면에서 부담이 될 가능성이 높습니다. 제 경우에는 테스트 환경이기 때문에 버퍼 캐시도 아주 작고(60MB) 공유 풀도 그리 크지 않지만, 운영 장비인 경우에는 GRD를 위해서 꽤 많은 메모리 공간이 필요하게 됩니다.

select *
from (select inst_id, pool, name, round(bytes/1024/1024,0) size_MB
      from   gv$sgastat
      where  name in ('gcs resources',
                      'gcs shadows',
                      'ges enqueues',
                      'ges resource dynamic',
                      'ges resource permanent'))
pivot (max(size_MB) for inst_id in (1,2,3))
order by name
/
POOL         NAME                               1          2          3
------------ ------------------------- ---------- ---------- ----------
shared pool  gcs resources                      3          3          3
shared pool  gcs shadows                        2          2          2
shared pool  ges enqueues                       8          7          7
shared pool  ges resource dynamic               0          1          1
shared pool  ges resource permanent             4          4          4

  • [18] 블록 마스터 해싱과 관련된 _lm_contiguous_res_count 파라미터 동작 방식 확인 바로가기

  • 저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License
    TAG GRD

    [16] X$BH, X$LE, X$KJBL을 이용한 마스터 노드 확인 방법

    RAC 2016.07.29 04:28 Posted by 시연아카데미

    현재 RAC GRD (Global Resource Directory)에 대해서 연구중입니다. GRD의 동작원리를 파악하기 위해서는 리소스 마스터 노드 및 사용 노드에 대한 분석이 필수적이며 이를 위해 주로 3개의 X$ 테이블을 이용합니다.

    • X$BH   (버퍼 헤더 구조 파악)  : V$BH의 베이스 테이블
    • X$LE   (락 엘리먼트 구조 파악) : V$LOCK_ELEMENT의 베이스 테이블
    • X$KJBL (BL 락 구조 파악)     : V$GES_ENQUEUE의 베이스 테이블


    V$를 이용하지 못하는 이유는 V$에는 각 뷰간의 조인에 필요한 연결고리 칼럼이 제공되지 않기 때문입니다. 따라서 부득이하게 X$를 이용합니다. X$ 간의 연결고리 칼럼은 다음과 같습니다.

    • X$BH.LE_ADDR = X$LE.LE_ADDR 
    • X$LE.LE_KJBL = X$KJBL.KJBLLOCKP 

     
     
    그런데 X$를 이용하면 불편한 점이 몇 가지 있습니다. SYS 유저로만 조회가 가능하다는 점과 GV$ 뷰와 같이 모든 노드의 X$ 정보를 한번에 확인할 수 있는 방법이 없다는 점입니다. 이러한 불편함을 해소하기 위해 다음과 같이 별도의 뷰(X_$)를 생성한 후 해당 뷰에 권한을 부여하고, DB Link를 이용해서 RAC 모든 노드의 X_$ 뷰를 한번에 조회할 수 있는 GX$ 뷰를 생성합니다. 그리고 GX$ 뷰를 이용해서 오브젝트 및 블록의 마스터 노드 및 사용 노드 정보를 확인할 수 있는 스크립트를 생성합니다. (시노님과 DB Link를 public으로 설정한 점은 단순히 편의성 때문이므로 보안을 요하는 경우에는 private로 설정하시면 됩니다)


    [수정사항. 2016.08.02]

    테스트를 진행하다보니 스크립트가 꽤 많이 필요합니다. 따라서, 구글 사이트를 이용해서 스크립트를 관리하기로 했습니다. https://sites.google.com/site/siyeon70/sql-scripts 따라서, 아래의 스크립트는 사용하지 않습니다.


    테스트 환경 : RAC 3 Node: 12.1.0.2 64bit


    1) 1번 노드에서 SYS 유저로 X_$ 뷰 생성 및 시노님 생성

    sqlplus / as sysdba
    create or replace view x_$bh_1   as select 'OOW1' inst_name, a.* from x$bh   a;
    create or replace view x_$le_1   as select 'OOW1' inst_name, a.* from x$le   a;
    create or replace view x_$kjbl_1 as select 'OOW1' inst_name, a.* from x$kjbl a;


    create public synonym x_$bh_1   for x_$bh_1;
    create public synonym x_$le_1   for x_$le_1;
    create public synonym x_$kjbl_1 for x_$kjbl_1;


    grant all on x_$bh_1   to public;
    grant all on x_$le_1   to public;
    grant all on x_$kjbl_1 to public;

    2) 2번 노드에서 SYS 유저로 X_$ 뷰 생성 및 시노님 생성

    sqlplus / as sysdba
    create or replace view x_$bh_2   as select 'OOW2' inst_name, a.* from x$bh   a;
    create or replace view x_$le_2   as select 'OOW2' inst_name, a.* from x$le   a;
    create or replace view x_$kjbl_2 as select 'OOW2' inst_name, a.* from x$kjbl a;

    create public synonym x_$bh_2   for x_$bh_2;
    create public synonym x_$le_2   for x_$le_2;
    create public synonym x_$kjbl_2 for x_$kjbl_2;


    grant all on x_$bh_2   to public;
    grant all on x_$le_2   to public;
    grant all on x_$kjbl_2 to public;


    3) 3번 노드에서 SYS 유저로 X_$ 뷰 생성 및 시노님 생성

    sqlplus / as sysdba
    create or replace view x_$bh_3   as select 'OOW3' inst_name, a.* from x$bh   a;
    create or replace view x_$le_3   as select 'OOW3' inst_name, a.* from x$le   a;
    create or replace view x_$kjbl_3 as select 'OOW3' inst_name, a.* from x$kjbl a;

    create public synonym x_$bh_3   for x_$bh_3;
    create public synonym x_$le_3   for x_$le_3;
    create public synonym x_$kjbl_3 for x_$kjbl_3;

    grant all on x_$bh_3   to public;
    grant all on x_$le_3   to public;
    grant all on x_$kjbl_3 to public;


    4) 1번 노드에서 SYS 유저로 DB Link 생성

    TNSNAMES.ORA 보기

    sqlplus / as sysdba

    create public database link OOW1 using 'OOW1';
    create public database link OOW2 using 'OOW2';
    create public database link OOW3 using 'OOW3';


    5) 1번 노드에서 SCOTT 유저로 GX$ 뷰 생성

    create or replace view gx$bh as
    select * from sys.x_$bh_1
    union all
    select * from sys.x_$bh_2@oow2
    union all
    select * from sys.x_$bh_3@oow3;

    create or replace view gx$le as
    select * from sys.x_$le_1
    union all
    select * from sys.x_$le_2@oow2
    union all
    select * from sys.x_$le_3@oow3;

    create or replace view gx$kjbl as
    select * from sys.x_$kjbl_1
    union all
    select * from sys.x_$kjbl_2@oow2
    union all
    select * from sys.x_$kjbl_3@oow3;


    6) 스크립트 생성
    -------------------------------------------------------------------
    -- 파일명 : fnd_obj_master.sql
    -- 목적  : 입력된 오브젝트명을 이용해서 해당 블록들의 마스터 노드 및 사용 노드 확인
    -- 사용법 : @fnd_obj_master <오브젝트명>
    -------------------------------------------------------------------

    set  verify off linesize 1000  pages 1000

    define __OBJECT_NAME=&1

    select /*+ leading (a b c) */
           a.inst_name,
           a.class,
           a.dbablk,
           c.kjblname,
           c.kjblgrant,
           c.kjblrequest,
           c.kjblmaster,
           c.kjblowner
    from   gx$bh   a,
           gx$le   b,
           gx$kjbl c
    where  a.obj     = (select object_id from user_objects where object_name=&__OBJECT_NAME)
    and    a.state  <> 3 -- exclude CR block
    and    a.le_addr   = b.le_addr
    and    b.le_kjbl   = c.kjbllockp
    and    a.inst_name = b.inst_name
    and    b.inst_name = c.inst_name
    order by 1,3;


    sselect /*+ leading (a b c) */
           a.inst_name,
           c.kjblmaster,
           c.kjblowner,
           count(*) cnt
    from   gx$bh   a,
           gx$le   b,
           gx$kjbl c
    where  a.obj     = (select object_id from user_objects where object_name=&__OBJECT_NAME)
    and    a.state  <> 3 -- exclude CR block
    and    a.le_addr   = b.le_addr
    and    b.le_kjbl   = c.kjbllockp
    and    a.inst_name = b.inst_name
    and    b.inst_name = c.inst_name
    group by a.inst_name, c.kjblmaster, c.kjblowner
    order by 1;


    -------------------------------------------------------------------
    -- 파일명 : fnd_blk_master.sql
    -- 목적  : 특정 블록 1개의 마스터 노드 및 사용 노드 확인
    -- 사용법 : @fnd_blk_master <오브젝트명> <블록번호>
    -------------------------------------------------------------------

    set  verify off linesize 1000  pages 1000

    define __OBJECT_NAME=&1
    define __BLOCK_NO=&2

    select /*+ leading (a b c) */
           a.inst_name,
           a.class,
           a.dbablk,
           c.kjblname,
           c.kjblname2,
           c.kjblgrant,
           c.kjblrequest,
           c.kjblmaster,
           c.kjblowner
    from   gx$bh   a,
           gx$le   b,
           gx$kjbl c
    where  a.obj     = (select object_id from user_objects where object_name='&__OBJECT_NAME')
    and    a.dbablk  = &__BLOCK_NO           
    and    a.state  <> 3 -- exclude CR block
    and    a.le_addr   = b.le_addr
    and    b.le_kjbl   = c.kjbllockp
    and    a.inst_name = b.inst_name
    and    b.inst_name = c.inst_name
    order by 1,3;


    제 경우, 연구의 편의성을 위해서 GX$ 뷰를 생성한 것이므로, GX$ 뷰 생성이 여의치 않은 경우에는 X$ 테이블을 이용해서 스크립트를 작성하셔도 됩니다. 단, 그럴 경우 모든 노드에서 각각 수행해야 하는 불편함이 있습니다. 앞으로 진행되는 연구에서는 위의 2개의 스크립트를 이용할 예정입니다.

    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    [15] RAC Interconnect, HAIP에 대한 가벼운 정리

    RAC 2016.07.26 22:19 Posted by 시연아카데미

    들어가기에 앞서


    이번 시간에 다룰 내용은 RAC 네트워크의 핵심 부분인 Interconnect와 관련된 몇 가지 내용입니다. 네트워크 분야는 제가 잘 모르는 분야이므로 학습한 내용을 바탕으로 DBA들이 알면 도움이 될 만한 몇 가지 내용들과 제가 궁금했던 몇 가지 내용을 정리하는 수준으로 글을 작성했습니다. 여기 나오는 대부분의 내용은 아래 책의 내용을 참고했습니다.



    질문1. 인터커넥트용 NIC는 어떻게 확인할 수 있나요?


    오라클은 다양한 방법으로 인터커넥트용 NIC를 확인할 수 있는 방법을 제공합니다.


    1. $GRID_HOME/bin/oifcfg 명령어를 이용한 방법

    [oracle@rac1 SS]$ oifcfg getif
    eth0  192.168.56.0  global  public
    eth1  192.168.10.0  global  cluster_interconnect


    Note
    명령어 수행 결과 eth1 NIC가 인터커넥트용임을 알 수 있습니다.


    [oracle@rac1 SS]$ oifcfg iflist -p -n
    eth0  192.168.56.0  PRIVATE  255.255.255.0
    eth1  192.168.10.0  PRIVATE  255.255.255.0
    eth1  169.254.0.0   UNKNOWN  255.255.0.0
    eth2  10.0.4.0      PRIVATE  255.255.255.0


    Note
    명령어 수행 결과 eth1에는 2개의 IP 대역이 설정되어 있음을 알 수 있습니다. 169.254.0.0은 11gR2부터 제공되는 HAIP 대역대입니다. 따라서 명령어 수행결과 에 169.254.0.0이 출력된다면 해당 시스템은 HAIP를 사용하는 것입니다. (HAIP는 질문-2 참조)


    2. X$KSXPIA fixed 테이블 및 GV$CLUSTER_INTERCONNECTS 뷰를 이용한 방법 select pub_ksxpia  as is_public,
           name_ksxpia as name,
           ip_ksxpia   as ip_address
    from   x$ksxpia;

    IS_PUBLIC  NAME            IP_ADDRESS
    ---------- --------------- ----------------
    N          eth1:1          169.254.237.87


    select inst_id,
           name,
           ip_address,
           is_public
    from   gv$cluster_interconnects
    order by inst_id;

       INST_ID NAME            IP_ADDRESS       IS_
    ---------- --------------- ---------------- ---
             1 eth1:1          169.254.237.87   NO
             2 eth1:1          169.254.240.162  NO


    Note
    쿼리 수행 결과를 통해 인터커넥트용 NIC는 eth1:1이며 실제 IP도 확인할 수 있습니다. 여기서 보이는 인터커넥트용 IP가 /etc/hosts 파일에 설정한 private ip와 다른 경우에는 11gR2부터 제공하는 HAIP를 사용하고 있다고 보시면 됩니다. (HAIP는 질문-2 참조)


    3. ALERT LOG를 이용한 방법

    LICENSE_MAX_SESSION = 0
    LICENSE_SESSIONS_WARNING = 0
    Initial number of CPU is 2
    Number of processor cores in the system is 2
    Number of processor sockets in the system is 1
    Private Interface 'eth1:1' configured from GPnP for use as a private interconnect.
      [name='eth1:1', type=1, ip=169.254.237.87, mac=08-00-27-27-95-03, net=169.254.0.0/16, mask=255.255.0.0, use=haip:cluster_interconnect/62]
    Picked latch-free SCN scheme 3


    Note
    Alert Log에서도 인터커텍트용 NIC, IP, HAIP 사용 여부등을 확인할 수 있습니다.



    질문-2. HAIP란 무엇인가요?


    HAIP (Highly Available IP)에 대한 설명은 아래의 2개의 문서를 참고하시면 좋습니다.

    간단히 요약하면, 기존에는 NIC의 이중화를 위해 OS 레벨의 NIC 본딩과 같은 기법을 사용했으나, 11gR2부터는 이러한 이중화 역시 GI (Grid Infrastructure)에서 관리하겠다는 것입니다.예를 들어 1개의 private network을 설정했다면 (예 eth1: 192.168.10.1) 해당 NIC에 169.254로 시작되는 HAIP가 자동으로 설정됩니다. (예시-1 참조) HAIP는 최대 4개까지 설정이 가능하며 이를 통해 가용성과 성능 향상을 꾀함과 동시에 기존에 OS 의존적이던 부분들을 점차적으로 GI 안의 관리포인트로 끌어들인다는 의미로도 해석할 수 있습니다.


    예시-1. HAIP 예제

    [oracle@rac1 SS]$ ifconfig -a
    eth1      Link encap:Ethernet  HWaddr 08:00:27:27:95:03
              inet addr:192.168.10.1  Bcast:192.168.10.255  Mask:255.255.255.0
              inet6 addr: fe80::a00:27ff:fe27:9503/64 Scope:Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:7991199 errors:0 dropped:0 overruns:0 frame:0
              TX packets:7288897 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:1000
              RX bytes:5681272569 (5.2 GiB)  TX bytes:4967857149 (4.6 GiB)

    eth1:1    Link encap:Ethernet  HWaddr 08:00:27:27:95:03
              inet addr:169.254.237.87  Bcast:169.254.255.255  Mask:255.255.0.0
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1


    [oracle@rac1 SS]$ cat /etc/hosts
    127.0.0.1   localhost localhost.dbaora.com
    #public
    192.168.56.2    ap1         ap1.dbaora.com
    192.168.56.71   rac1        rac1.dbaora.com
    192.168.56.72   rac2        rac2.dbaora.com
    #private
    192.168.10.1    rac1-priv   rac1-priv.dbaora.com
    192.168.10.2    rac2-priv   rac2-priv.dbaora.com



    질문3. 인터커넥트용 NIC 속도는 어떻게 확인할 수 있을까요?


    ethtool 명령어를 이용해서 NIC 속도를 확인할 수 있습니다. 명령어 수행 후에 Speed 부분을 확인하면 됩니다.


    [oracle@rac1 SS]$ ethtool eth1
    Settings for eth1:
            Supported ports: [ TP ]
            Supported link modes:   10baseT/Half 10baseT/Full
                                    100baseT/Half 100baseT/Full
                                    1000baseT/Full
            Supported pause frame use: No
            Supports auto-negotiation: Yes
            Advertised link modes:  10baseT/Half 10baseT/Full
                                    100baseT/Half 100baseT/Full
                                    1000baseT/Full
            Advertised pause frame use: No
            Advertised auto-negotiation: Yes
            Speed: 1000Mb/s
            Duplex: Full
            Port: Twisted Pair
            PHYAD: 0
            Transceiver: internal
            Auto-negotiation: on
            MDI-X: off (auto)
    Cannot get wake-on-lan settings: Operation not permitted
            Current message level: 0x00000007 (7)
                                   drv probe link
            Link detected: yes
      



    질문-4. 네트워크 관련 주요 파라미터는 무엇이고 어떻게 확인할 수 있을까요?


    인터커넥트의 성능을 위해서는 TCP 관련 파라미터인 net.core.rmem_max, net.core.wmem_max, net.ipv4.tcp_rmem, net.ipv4.tcp_wmem 설정이 매우 중요합니다. 해당 내용에 대해서는 아래의 블로그를 꼭 한번씩 보시기 바랍니다. 아주 자세하고 정확하게 기술되어 있습니다.

    해당 설정 값들은 sysctl -p로 확인할 수 있으며, 아래와 같이 V$OSSTAT 뷰를 통해서도 확인이 가능합니다.


    col "net.ipv4.tcp_wmem"  for a30
    col "net.ipv4.tcp_rmem"  for a30
    col "net.core.wmeme_max" for a10
    col "net.core.rmeme_max" for a10
    select
        max(decode(stat_name,'TCP_SEND_SIZE_MIN',       value))||' '||
        max(decode(stat_name,'TCP_SEND_SIZE_DEFAULT',   value))||' '||
        max(decode(stat_name,'TCP_SEND_SIZE_MAX',       value)) "net.ipv4.tcp_wmem",
        max(decode(stat_name,'TCP_RECEIVE_SIZE_MIN',    value))||' '||
        max(decode(stat_name,'TCP_RECEIVE_SIZE_DEFAULT',value))||' '||
        max(decode(stat_name,'TCP_RECEIVE_SIZE_MAX',    value)) "net.ipv4.tcp_rmem",
        max(decode(stat_name,'GLOBAL_SEND_SIZE_MAX',    value)) "net.core.wmem_max",
        max(decode(stat_name,'GLOBAL_RECEIVE_SIZE_MAX', value)) "net.core.rmem_max"
    from v$osstat


    net.ipv4.tcp_wmem  net.ipv4.tcp_rmem   net.core.wmem_max net.core.rmem_max
    ------------------ ------------------- ----------------- -----------------
    4096 16384 4194304 4096 87380 6291456  1048576           4194304



    질문-5. 특정 시점의 RAC 노드 간의 PING 속도를 확인할 수 있는 방법이 있을까요?


    오라클은 11g부터 ping 프로세스를 이용해서 노드 간의 ping 속도 (500바이트, 8Kb)를 측정합니다. 조금 아쉬운 부분은 ping 프로세스가 주기적으로 (대략 10여초에 1회) 체크한 성능 정보는 실시간 뷰로는 제공되지 않으며 DBA_HIST_INTERCONNECT_PINGS 테이블을 통해서 집계된 정보만을 제공한다는 점입니다.



    글을 마치며


    이상으로 간단하게 RAC 네트워크 부분을 정리했습니다. 제가 하드웨어 적인 백그라운드 지식이 없다 보니 설치, 구성, HA, 서비스, ASM, 네트워크 부분의 학습에 오랜 시간이 걸렸습니다. 이제부터는 본격적으로 캐시 퓨전 동작원리 및 성능에 대해서 집중적으로 다룰 예정입니다. 기존 내용보다는 좀 더 흥미가 있으리라 생각됩니다.


    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    들어가기에 앞서


    ASM 자료 조사 시에 찾은 유용한 자료들을 먼저 소개합니다.

    • 굳어스 ASM 정리 자료 (기본 개념 정리부터 동작원리 및 테스트까지 정리가 잘 되어있습니다)
    • ASM FAQ 자료 (FAQ 형식으로 정리한 자료입니다. 아주 간단 명료하게 설명이 잘되어있습니다)
    • ASM 인터널 자료 : 구글에서 "A closer Look inside Oracle ASM - Luca Canali - CERN" 검색 후 나오는 첫 번째 PPT 자료

    ASM 자료들은 대부분 오래된 자료들입니다. 하지만 ASM 아키텍처의 변화가 크지 않았다는 점을 고려하면 아직도 유용한 자료라고 생각됩니다. 따라서 ASM 학습 시에 숙지하면 좋은 내용들입니다. 이번 포스팅에서는 기존 자료의 내용을 중복해서 다루기보다는 제가 궁금했던 몇 가지 사항들을 정리해보려고 합니다. 
     
     


    질문1. ASM 인스턴스는 무엇이고, 반드시 필요할까요?


    ASM(Automatic Storage Management)을 처음 접할때 가장 당황스러운 부분은 "ASM을 사용하기 위해서 별도의 ASM 인스턴스가 필요하다"는 사실입니다. ASM의 용도가 볼륨 매니저라는 점을 놓고 볼때 "별도의 인스턴스까지 운영해야할까?" 라는 의문점을 갖게 되는건 엔지니어로서는 자연스러운 일일겁니다. 저 역시 이부분이 궁금해서 여러가지 자료를 찾아봤지만, 명확한 내용을 기술해놓은 자료를 찾아볼 수는 없었습니다. 그마다 "A closer Look inside Oracle ASM - Luca Canali - CERN" 문서에 어느 정도 설득력 있는 내용이 정리되어있습니다.

    • 가벼운 인스턴스를 이용한 관리 (ASM 인스턴스는 리두로그, 데이터파일 등이 존재하지 않음)
    • SQL 명령어를 이용해서 환경 설정 가능 (사용 편의성)
    • V$ 뷰들을 통해 메타 정보 및 ASM 디스크 성능 정보 제공 (모니터링 편의성)
    • udump 및 bdump에 로그 기록 (문제 추적의 편의성)

    하지만, 아무리 가벼운 인스턴스라고 할지라도 11g까지는 1노드당 1개의 ASM 인스턴스가 필요하다는 점과 ASM 인스턴스가 다운될 경우 (이런 경우가 거의 없다고는 하지만) DB 인스턴스도 즉시 다운된다는 사실은 운영 입장에서 보면 민감한 사실임에 틀림없습니다.


    Note
    12c의 Flex ASM을 사용할 경우에 노드의 개수와 무관하게 일정 개수(ASM 카디날리티)의 ASM 인스턴스만을 사용하면 됩니다.




    질문2. ASM 환경에서 IO처리를 위해 ASM 인스턴스를 경유할까요?


    ASM 디스크의 extent map 은 ASM 인스턴스가 관리하므로, IO 시에 ASM 인스턴스를 경유할 것 같다는 생각을 할 수 있습니다. 하지만, ASM 인스턴스를 경유해서 IO를 처리한다면 성능 지연이 발생할 가능성이 높습니다. 따라서 오라클은 ASM 인스턴스를 경유하지 않고도 IO를 처리할 수 있도록, ASMB 프로세스를 이용해서 extent map 정보를 DB 인스턴스에게 제공합니다. ASMB 프로세스는 ASM 인스턴스, DB 인스턴스 각각 1개씩 구동되며, 각 ASMB 프로세스들은 오라클 쉐도우 프로세스를 각각 1개씩 fork 시켜 ASM 인스턴스에 접속합니다. (그림-1. 참조) 이러한 연결 고리(‘브릿지’)를 이용해서 DB 인스턴스와 ASM 인스턴스 간에 메타 정보를 전송하게 됩니다. Extent map 정보는 File Open 시에 전송 (10g는 전체 set 전송, 11g부터는 파일별로 n개의 정보만 전송한 후 필요 시에 전송)되므로, 이후의 DB IO는 ASM 인스턴스를 경유하지 않고도 처리가 가능하게 됩니다.


    그림-1. DB 인스턴스와 ASM 인스턴스 메타 정보 전송 및 리밸런싱 수행 구성도

     

    Note
    Extent Map 정보는 ASM 인스턴스의 X$KFFXP Fixed 테이블을 통해서만 확인할 수 있습니다. (DB 인스턴스에도 동일한 이름의 테이블이 있지만 0건임)




    질문3. ASM 환경에서 디스크 리밸런싱은 어떻게 처리될까요?


    ASM의 장점 중의 하나는 자동으로 디스크 리밸런싱을 수행하므로 DBA가 별도의 IO 튜닝 작업을 하지 않아도 된다는 것입니다. 예를 들어, 디스크 그룹에 디스크가 추가된 경우에 자동으로 리밸런싱을 수행합니다. (수동 수행도 가능) 이를 위해 ASM 인스턴스는 RBAL (Rebalance Master) 프로세스를 이용해서 리밸런싱 작업을 코디네이트하고 1개 이상의 ARB 프로세스들을 이용해서 실제 리밸런싱 처리를 수행하도록 합니다. ARB 프로세스는 리밸런싱 업무 시에만 구동됩니다.




    질문4. DB 인스턴스와 ASM 인스턴스에 존재하는 V$ASM_ 뷰들은 동일한 내용을 제공하나요?


    DB 인스턴스와 ASM 인스턴스에서는 동일한 이름의 V$ASM_ 뷰들이 존재합니다. 그렇다면 "제공되는 내용도 동일할까?" 라는 궁금증이 생기게 됩니다. 결론부터 이야기하면 ASM 인스턴스는 ASM 디스크그룹을 제공하는 입장이고 DB 인스턴스는 ASM 디스크그룹을 사용하는 입장이라는 점을 제외하곤 거의 동일한 정보를 제공합니다. 예를 들면, ASM 인스턴스의 V$ASM_DISKGRUOP.STATE에는 'MOUNTED'로 표시되는 것에 비해서, DB 인스턴스에서는 'CONNECTED'라고 표시되는 정도의 차이점이 있습니다.

     

    그리고 아래의 뷰들을 조회하면, ASMB 프로세스를 이용한 '브릿지'를 통해 ASM 인스턴스로부터 결과를 전송 받게 됩니다.  즉, ASM 구성정보, 디스크 정보 등 다이나믹하게 변경 가능한 정보들은 항상 ASM 인스턴스를 통해서 최신 정보를 전달 받는다고 보면 될 것 같습니다.


    V$ASM_ATTRIBUTE;
    V$ASM_DISK
    V$ASM_DISK_STAT;
    V$ASM_FILE;



    글을 마치며


    ASM은 다소 싱겁게 마무리된 측면이 있습니다. 일반적인 개념을 정리하기에는 이미 정리가 너무 잘 되어있고, "How"를 고민하기에는 그렇게 많은 고민 포인트가 없기 때문이기도 합니다. 다만, ASM을 사용하기 위해서는 ASM 인스턴스가 필요하고, ASM 인스턴스와 DB 인스턴스 간의 데이터 전송은 어떻게 이루어지고, 리밸런싱은 누가 수행하고, V$ASM 뷰들은 왜 동일한 내용을 각 인스턴스에서 제공하는지에 대한 가벼운 대답을 정리하는 수준으로 ASM을 마무리 하려고 합니다. 방문자가 많은 블로그도 아니고, 연재라고 해서 아직까지는 기다리는 독자가 있는 건 아니지만 늘 하나의 글을 마무리한 후에는 새로운 마음으로 다음 주제를 잡고 있습니다. 다음 주제는 "RAC 네트워크"입니다. 이 또한 정리할 내용이 많을지는 모르겠습니다. "RAC 네트워크"가 마무리되면 RAC 연재에서 가장 재미있을 만한 "캐시퓨전 및 RAC 옵타마이징"이라는 주제를 다룰 예정입니다.


    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    [13] UCP 기반의 FCF (Fast Connection Failover) 설명

    RAC 2016.07.14 00:37 Posted by 시연아카데미

    이번 시간에는 UCP (Universal Connection Pool) 기반의 FCF (Fast Connection Failover)의 동작 방식에 대해서 설명하도록 하겠습니다.



     

    13-1. FCF (Fast Connection Failover)란?


    FCF는 말 그대로 빠른 커넥션 페일오버를 제공하는 기능입니다. UCP 기반의 FCF는 다음과 같이 동작합니다.

    1. 빠른 DB 장애 인지를 위해 ONS (Oracle Notification Service) 기반의 FAN 메세지를 이용한 push 방식을 통해 "INSTANCE down" 메세지를 전송 받습니다. (polling 방식이 아니므로 pooling interval 만큼의 delay도 발생하지 않습니다)
    2. 톰캣 서버는 "INSTANCE down" 메세지를 전송 받은 후, 기존 커넥션을 정리하고 Failover 노드에 신규 커넥션을 연결합니다. 
    3. 톰캣 서버는 "INSTANCE Up" 메세지를 전송 받은 후 일정 시간이 지나면, Failover 노드의 커넥션을 정리하고 기존 노드로 신규 커넥션을 연결합니다.
       

    동작원리를 통해 알 수 있듯이 UCP 기반의 FCF는 JDBC Connection Pool에 비해 2가지 장점을 가집니다.

    • Failover 노드로의 커넥션 연결을 "Instance down" 메시지를 받은 즉시 수행 (JDBC Connection Pool은 사용자 요청 시점에 수행)
    • DB가 정상화된 후에 커넥션 자동 원복 (JDBC Connection Pool은 사용자의 수동 재시작 필요)
       


    13-2. FCF 동작 원리


    그림을 통해 FCF의 동작원리를 살펴보도록 하겠습니다.


    CONTEXT.XML 보기



    UCP로 첫 번째 요청이 처리된 이후에는 "그림-1"과 같이 minPoolSize 파라미터에 지정된 3개의 커넥션이 RAC1 인스턴스에 연결된 상태가 됩니다.


    그림-1


    Note
    UCP에서 FCF를 사용하기 위해서는 fastConnectionFailoverEnabled 파라미터를 true로 설정하면 됩니다.  


    RAC1 인스턴스의 장애가 발생하면 다음과 같은 일련의 일들이 발생합니다. (그림-2 참조)

    • RAC1에 연결된 세션 비정상 종료
    • RAC1 세션에 연결된 UCP 커넥션 객체들 상태가 Stale로 변경 
    • RAC1 노드의 ONS 프로세스는 "INSTANCE down" FAN 메세지를 톰캣 서버로 전달  

    그림-2

     



    FAN 메세지를 전달받은 톰캣 서버는 다음과 같은 일들을 수행합니다. (그림-3 참조)

    • Stale 커넥션 클린업
    • Failover노드로 minPoolSize에 정의된 개수만큼 커넥션 연결  

    그림-3




    RAC1 인스턴스가 복구된 직후에, ONS는 "INSTANCE up" FAN 메세지를 톰캣 서버로 전달합니다 (그림-4 참조)

    그림-4





    "INSTANCE up" FAN 메세지를 전달 받은 톰캣 서버는 inactiveConnectionTimeout 설정 시간 이후에 2번 노드의 idle 커넥션을 종료한 후, 1번 노드로 커넥션을 연결합니다. (그림-5 참조)

    그림-5





    13-3. inactiveConnectionTimeout 파라미터 동작 방식


    테스트 결과, UCP는 inactiveConnectionTimeout 주기 마다 idle 커넥션을 종료하고 다시 커넥션을 생성하는 것으로 확인되었습니다. 예를 들어, inactiveConnectionTimeout=60, minPoolSize=10 으로 설정했고, 60초동안 아무 일도 없다면 10개의 커넥션이 Close된 후에 다시 생성됩니다. 주의할 점은, 이때 10개의 DB 세션 또한 릴리즈 된 후에 다시 생성(fork)된다는 점입니다. 이러한 동작 방식은 V$SESSION.LOGON_TIME의 변화 및 V$SYSSTATlogon cumulative 지표의 증가를 통해서 관찰할 수 있습니다. 따라서 UCP를 사용할 경우에는 시스템의 워크로드에 맞게 inactiveConnectionTimeout, minPoolSize 값을 적절히 설정해야 합니다.



    참고 사이트


    http://www.hhutzler.de/blog/testing-ucp-connections-with-fcf-against-a-rac-12-1-0-2-database/



    글을 마치며


    이 글을 끝으로 로드 밸런싱과 Failover에 대한 기본적인 설명은 마무리가 된 것 같습니다. 다음 시간에는 RAC 아키텍처 중에서 가장 중요한 부분 중의 하나인 ASM에 대해서 다룰 예정입니다.



    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    이번 시간에는 톰캣 서버 + UCP + JSP + Jmeter를 이용해서 RLB 동작 방식을 파악해보도록 하겠습니다.



     

     

    준비 사항


    다음 사항을 준비합니다.


    1. Jmeter 설치


    Jmeter 설치는 여기를 참고하세요.
     
    2. UCP 구성
    지난 포스팅을 참고하세요.


    3. 샘플 JSP 작성 (load.jsp)


    load.jsp의 핵심은 노드에 따라서 쿼리 성능의 편차를 크게 하는 것입니다. 이를 위해, 인스턴스 명을 기준으로 쿼리를 분기해서 처리했습니다.

    LOAD.JSP 보기


    4. 성능 정보를 수집할 스크립트 생성 (save_load.sql)


    save_table을 생성한 후, save_load.sql을 이용해서 서비스의 로드 및 시스템 상황을 저장합니다.

    SAVE_LOAD.SQL 보기


    이제 모든 준비가 끝났습니다. 그럼 테스트를 시작합니다.




    12-1. UCP + CLB_GOAL=SHORT / RLB_GOAL=SERVICE_TIME 인 서비스 (ONLINE_UCP)를 이용한 부하 테스트


    아래 순서대로 테스트를 진행합니다.


    1. 톰캣 서버 기동


    [root@ap1 ~]# service tomcat start
    Using CATALINA_BASE:   /usr/local/tomcat
    Using CATALINA_HOME:   /usr/local/tomcat
    Using CATALINA_TMPDIR: /usr/local/tomcat/temp
    Using JRE_HOME:        /usr/local/java
    Using CLASSPATH:       /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar


    2. 커넥션 풀 연결 확인


    UCP는 톰캣 기동 시에 커넥션을 연결하지 않고, 첫 번째 요청이 들어오는 시점에 커넥션을 연결합니다. 따라서, 현재 시점에는 ONLINE_UCP 서비스로 연결된 세션은 없습니다.
    select 'INST_1' as inst_id, count(*) total_cnt,
           sum(decode(service_name,'ONLINE_DBCP',1)) online_dbcp,
           sum(decode(service_name,'ONLINE_UCP' ,1)) online_ucp,
           sum(decode(service_name,'SHORT_SRV'  ,1)) short_srv,
           sum(decode(service_name,'LONG_SRV'   ,1)) long_srv
    from gv$session where inst_id=1
    union all
    select 'INST_2' as inst_id, count(*) total_cnt,
           sum(decode(service_name,'ONLINE_DBCP',1)),
           sum(decode(service_name,'ONLINE_UCP' ,1)),
           sum(decode(service_name,'SHORT_SRV'  ,1)),
           sum(decode(service_name,'LONG_SRV'   ,1))
    from gv$session where inst_id=2;


    INST_I  TOTAL_CNT ONLINE_DBCP ONLINE_UCP  SHORT_SRV   LONG_SRV
    ------ ---------- ----------- ---------- ---------- ----------
    INST_1         74           6                     6          6
    INST_2         67           4                     4          4


    3. UCP 연결


    UCP는 최초 요청 직후에 커넥션을 연결합니다. 이전 포스팅에서 작성한 test.jsp를 수행한 후, 커넥션 연결 여부를 확인합니다.

    INST_I  TOTAL_CNT ONLINE_DBCP ONLINE_UCP  SHORT_SRV   LONG_SRV
    ------ ---------- ----------- ---------- ---------- ----------
    INST_1         87           6         13          6          6
    INST_2         74           4          7          4          4


    4. 로드 저장용 스크립트 수행


    save_load.sql을 이용해서 5초에 1번씩 부하 상황을 저장합니다.

    [oracle@rac1 ~]$ while true
    > do
    > sqlplus apps/apps @save_load.sql
    > sleep 5
    > done


    5. Jmeter로 Run 테스트


    다음과 같이 Jmeter를 설정한 후 실행합니다.





    12-2. 결과 분석


    테스트가 끝난 후에, 다음 쿼리를 이용해서 수행 결과를 분석합니다.


    결과 분석용 쿼리 보기


    결과-1. 아래 그래프와 같이, DBTIMEPERCALL 시간이 짧은 2번 노드로 커넥션 풀 세션이 이전하는 것을 알 수 있습니다. 즉, RLB가 정상적으로 이루어졌습니다. (그림-1, 그림-2. 참조)


    그림-1. 노드 별 DBTIMEPERSEC 트렌드


    그림-2. 노드 별 커넥션 풀 세션 수 트랜드



    결과-2. RLB가 정상적으로 이루어짐에 따라서, 1번 노드의 active 세션 개수가 점차적으로 줄어드는 것을 확인할 수 있습니다. (그림-3. 참조)


    그림-3. 노드 별 Active 세션 수 트랜드



    결과-3. CPU 런-큐 및 CPU(%)은 RLB와는 무관한것으로 확인됩니다. (그림-4, 그림-5. 참조) 즉, 해당 값들 커넥션 시점의 로드 밸런싱(CLB)를 위해서만 사용됩니다. 그리고 커넥션 풀 세션들이 2번 노드로 이전함에 따라, 1번 노드의 CPU(%)이 점차적으로 감소하는 것을 확인할 수 있습니다.


    그림-4. 노드 별 CPU Run-Queue 트렌드


    그림-5. 노드 별 CPU(%) 트렌드



    12-3 결과 요약


    상기 예제를 통해 UCP 환경에서의 RLB 동작 방식을 확인했습니다. 나머지 3개의 서비스에 대한 테스트 겱는 지면 관계상 요약 정리만 하도록 하겠습니다. (표-1. 참조)


    표-1. 서비스 유형 별 테스트 결과 요약

     서비스 명

     구성

     영향받는 항목

     RLB

    여부

     GOODNESS

     DELTA

     LONG_SRV

    CLB_GOAL=LONG
    DBCP

     커넥션 시,

    "해당 서비스의 세션 수"

     X

     세션 수

     1

     SHORT_SRV

     CLB_GOAL=SHORT
     RLB_GOAL=NONE

     DBCP

     커넥션 시,

    "CPU 사용률(%)"

     X

     낮을수록 좋음
    최대값

    (CPU수*5000)

     가변적

     ONLINE_DBCP

     CLB_GOAL=SHORT

    RLB_GOAL=SERVICE_TIME
    DBCP

     커넥션 시,

    "CPU 사용률(%)"

     X

     상동

     가변적

     ONLINE_UCP

     CLB_GOAL=SHORT
    RLB_GOAL=SERVICE_TIME
    UDP

     커넥션 시,

    "CPU 사용률(%)"
    런타임 시,

    "콜당 수행 시간"

     O

     상동

     가변적


    글을 마치며


    4회의 연재를 통해 로드 밸런싱의 기본 개념 및 동작 원리를 살펴보았습니다. 테스트를 통해 원리를 검증 또는 역 추적한다는 것은 사실 굉장히 시간 소모적이고 위험할 수도 있는 (즉, 엉뚱한 결론에 이르는) 일입니다. 예를 들어, ONS.JAR 없이 UCP를 테스트했다면 지금과는 아주 상이한 결과가 나왔을 겁니다. 하지만, 다양한 역 추적 기법 (쿼리, 트레이스, OS 명령어 등)을 통해 원리를 이해해 나가는 과정은 재미있는 일임에 분명합니다. 다음 시간의 주제는 Failover 입니다. 다음 시간에 뵙겠습니다.

     


    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    똘똘님. 톰캣 서버에 UCP를 구성한 후에도 RLB가 동작하지 않는 것 같습니다. 제 생각으로는 RLB가 정상적으로 동작한다면 부하가 적은 노드로 커넥션이 이전해야 할 것 같은데 그렇게 동작하지 않습니다. 이유를 알 수 있을까요?



    네. UCP 구성의 핵심은 ONS.JAR를 설치해야 한다는 점입니다. 대부분의 문서에는 OJDBC7.JAR, UCP.JAR만 언급되어 있기 때문에 OJS.JAR를 설치해야 한다는 점을 놓치기 쉽습니다. RLB가 동작하기 위해서는 DB 서버의 ONS 프로세스와 AP 서버의 JAVA 프로세스 간의 통신이 필요하며, 이를 위해서는 AP 서버에 ONS.JAR가 필요합니다. 그럼 하나씩 살펴보도록 하겠습니다.

     

     



    테스트 환경


    • 톰캣 버전: apache-tomcat-7.0.70
    • JDB 버전: jdk1.7.0_79
    • 오라클 12c



    11-1. UCP를 위한 JAR 파일 복사


    AP 서버의 $CATALINA_HOME/lib 디렉토리에 ojdbc7.jar, ucp.jar, ons.jar를 복사합니다. DB 서버에 알맞은 jar 버전을 복사하는 것이 중요하므로, 해당 파일들을 DB 서버에서 복사해서 사용하는 것이 좋습니다. 


    DB 서버에서의 jar 파일의 위치

    • ojdbc7.jar : $ORACLE_HOME/jdbc/lib/ojdbc7.jar
    • ucp.jar    : $ORACLE_HOME/ucp/lib/ucp.jar
    • ons.jar    : $ORACLE_HOME/opmn/lib/ons.jar

      

    Note
    $ORACLE_HOME/oc4j/opmn/lib/ons.jar 파일을 사용할 경우 에러가 발생하니, 반드시 정확한 위치의 ons.jar 파일을 이용해야 합니다.




    11-2. UCP 구성을 위한 context.xml 편집


    다음과 같이 context.xml 파일을 편집합니다.
    [root@ap1 ~]# cd $CATALINA_HOME/webapps
    [root@ap1 webapps]# mkdir -p onlineucp/META-INF
    [root@ap1 webapps]# cd onlineucp/META-INF
    [root@ap1 META-INF]# vi context.xml

    <?xml version='1.0' encoding='utf-8'?>
    <Context>
        <WatchedResource>WEB-INF/web.xml</WatchedResource>
        <Manager pathname="" />
        <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
          <Resource
           name="jdbc/online_ucp"
           auth="Container"
           factory="oracle.ucp.jdbc.PoolDataSourceImpl"
           type="oracle.ucp.jdbc.PoolDataSource"
           description="UCP Pool in Tomcat"
           connectionFactoryClassName="oracle.jdbc.pool.OracleDataSource"
           minPoolSize="20"
           maxPoolSize="100"
           initialPoolSize="50"
           autoCommit="false"
           inactiveConnectionTimeout="20"
           fastConnectionFailoverEnabled="true"
           user="apps"
           password="apps"
           url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)
                (HOST=rac-scan)(PORT=1521))(CONNECT_DATA=
                (SERVICE_NAME=ONLINE_UCP)))"
           connectionPoolName="UCPPool"
           validateConnectionOnBorrow="true"
           sqlForValidateConnection="select 1 from DUAL" />
    </Context>




    11-3. 샘플 JSP 생성


    RLB 테스트를 위한 샘플 JSP를 생성합니다. 아래 코드 중에서 PoolDataSource를 이용해서 getConnection()을 수행하는 부분을 주의해서 보시면 됩니다. [root@ap1 ~]# cd $CATALINA_HOME/webapps/online_ucp
    [root@ap1 online_ucp]# vi test.jsp

    <%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%>
    <%@ page import="java.sql.*"%>
    <%@ page import="javax.naming.*"%>
    <%@ page import="javax.sql.*"%>
    <%@ page import="oracle.ucp.jdbc.*"%>
    <%@ page import="oracle.ucp.admin.*"%>
    <html>
    <head>
    <body >
    <%
            String   v1 = null;
            Connection conn=null;
            Statement st=null;
            ResultSet rs=null;<>
            try {
                    Context ctx = new InitialContext();
                    Context envContext  = (Context) ctx.lookup("java:/comp/env");
                    javax.sql.DataSource ds = (javax.sql.DataSource) envContext.lookup("jdbc/online_ucp");
                    PoolDataSource pds = (PoolDataSource) ds;
                    conn = pds.getConnection();
                   
                    st=conn.createStatement();
                    
                    String sql = "select 'Welcome UCP' from dual";
                    rs = st.executeQuery(sql);
                    rs.next();
                    v1 = rs.getString(1);
    %>
                    <%=v1 %>
    <%
            } catch (Exception e){
                    e.printStackTrace(System.out);
            }
            finally {
                    st.close();
                    rs.close();
                    conn.close();
            }
    %>
    </body>
    </html>




    11-4. 톰캣 서버 기동 및 ONS 통신 여부 확인


    톰캣 서버를 기동한 후에 DB 서버의 ONS 프로세스와의 통신 여부를 확인해보겠습니다. UCP는 초기 접속이 이루어진 후부터 커넥션이 연결되므로 다음 순서대로 진행합니다.
    • $ service tomcat start 
    • http://192.168.56.2:8080/online_ucp/test.jsp 수행


    AP 서버에서 6200 포트 사용 여부 확인

    root@ap1 ~]# lsof -i:6200
    COMMAND   PID USER   FD   TYPE DEVICE SIZE/OFF NODE NAME
    java    15267 root  178u  IPv6  77093      0t0  TCP ap1:58530->rac-scan:lm-x (ESTABLISHED)
    java    15267 root  179u  IPv6  77094      0t0  TCP ap1:13823->rac-scan:lm-x (ESTABLISHED)
    java    15267 root  180u  IPv6  77095      0t0  TCP ap1:56756->rac-scan:lm-x (ESTABLISHED)


    [root@ap1 ~]# ps -ef | grep 15267
    root     15267     1 34 15:23 pts/0    00:00:13 /usr/local/java/bin/java -Djava.util.logging.config.file=/usr/local/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Djdk.tls.ephemeralDHKeySize=2048 -Djava.endorsed.dirs=/usr/local/tomcat/endorsed -classpath /usr/local/tomcat/bin/bootstrap.jar:/usr/local/tomcat/bin/tomcat-juli.jar -Dcatalina.base=/usr/local/tomcat -Dcatalina.home=/usr/local/tomcat -Djava.io.tmpdir=/usr/local/tomcat/temp org.apache.catalina.startup.Bootstrap start


    DB 서버에서 6200 포트 사용 여부 확인

    [oracle@rac1 ~]$ lsof -i:6200
    COMMAND   PID   USER   FD   TYPE  DEVICE SIZE/OFF NODE NAME
    ons     19022 oracle    8u  IPv6 5934984      0t0  TCP *:lm-x (LISTEN)
    ons     19022 oracle   12u  IPv6 5948734      0t0  TCP rac1:lm-x->rac2:58878 (ESTABLISHED)
    ons     19022 oracle   13u  IPv6 9863440      0t0  TCP rac-scan:lm-x->ap1:56756 (ESTABLISHED)


    [oracle@rac1 SS]$ ps -ef | grep 19022
    oracle   19022 19021  0 Jul08 ?        00:00:01 /ora01/app/grid/product/12.1.0/grid/opmn/bin/ons -d


    [oracle@rac2 ~]$ lsof -i:6200
    COMMAND  PID   USER   FD   TYPE   DEVICE SIZE/OFF NODE NAME
    ons     3419 oracle    8u  IPv6 10175879      0t0  TCP *:lm-x (LISTEN)
    ons     3419 oracle    9u  IPv4 10175881      0t0  TCP rac2:58878->rac1:lm-x (ESTABLISHED)
    ons     3419 oracle   15u  IPv6 16250635      0t0  TCP rac-scan:lm-x->ap1:58530 (ESTABLISHED)
    ons     3419 oracle   16u  IPv6 16250636      0t0  TCP rac-scan:lm-x->ap1:13823 (ESTABLISHED)


    [oracle@rac2 ~]$ ps -ef | grep 3419
    oracle    3419  3418  0 Jul08 ?        00:00:00 /ora01/app/grid/product/12.1.0/grid/opmn/bin/ons -d


    Note
    AP 서버의 java 프로세스와 DB 서버의 ons 프로세스가 6200 포트로 연결되어 있음을 알 수 있습니다. DB 서버에서 생성된 서비스 매트릭스 정보는 해당 포트를 이용해서 AP 서버의 java 프로세스에게 전달되고, java 프로세스는 해당 정보를 이용해서 RBL를 수행하게 되는 것입니다. (그림-1. 참조)


    그림-1. ONS를 이용한 AP 서버와 DB 서버의 연결



    참고 문헌


    http://www.oracle.com/technetwork/database/application-development/planned-unplanned-rlb-ucp-tomcat-2265175.pdf


    글을 마치며


    이제 모든 환경 구성이 완료되었습니다. 다음 시간에는 Jmeter를 이용한 부하 테스트를 통해 RLB 동작 방식을 검증해보도록 하겠습니다.


    [12] Jmeter + 톰캣 + UCP를 이용한 RLB (Runtime Load Balancing) 동작 방식 검증 바로가기

    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    [10] CLB, RLB를 위한 서비스 매트릭스 정보의 흐름

    RAC 2016.07.08 20:28 Posted by 시연아카데미

    똘똘님! 이전 포스팅을 통해 CLB와 RLB의 기본 개념은 쉽게 이해했습니다. 이번 시간에는 로드 밸런싱을 위한 "서비스 매트릭스" 정보의 흐름에 대해서 알고 싶습니다. 




    네 궁금님. 말씀하신 것처럼 오라클은 로드 밸런싱을 위해 "서비스 매트릭스" 정보를 이용합니다. 테스트를 통해서 살펴보겠습니다.




    10-1. 리스너 설정


    로드 밸런싱을 위해서는 로컬 리스너와 리모트 리스너를 설정해야 합니다. 리스너는 대부분 설치 시에 자동으로 설정되므로 설정 내용만 확인하면 될 것입니다. 제 경우에는 SCAN IP를 사용하므로 remote_listener 설정 값이 rac-scan:1521로 나타납니다. SCAN을 사용하지 않는 환경에서는 상대 노드(들)의 리스너 주소가 출력되면 됩니다.
    1번 노드> show parameter _listener
    NAME                 VALUE
    -------------------- --------------------------------------------
    local_listener       (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.56.81)(PORT=1521))
    remote_listener      rac-scan:1521

    2번 노드> show parameter _listener
    NAME                 VALUE
    -------------------- --------------------------------------------
    local_listener       (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.56.82)(PORT=1521))
    remote_listener      rac-scan:1521



    10-2. 서비스 생성


    CLB 옵션 (LONG, SHORT)의 차이를 확인하기 위해 2개의 서비스 (LONG_SRV, SHORT_SRV)를 생성합니다. 또한, UCP (Universal Connection Pool) 환경에서만 RLB가 동작하는 것을 검증하기 위해 2개의 서비스 (ONLINE_DBCP, ONLINE_UCP)를 생성합니다. (표-1. 참조)


    표-1. 동작 차이 확인을 위한 4개의 서비스 목록

     서비스 명

     CLB_GOAL

     RLB_GOAL

     사용할 커넥션 풀

     LONG_SRV

     LONG

     n/a

     DBCP

     SHORT_SRV

     SHORT

     NONE

     DBCP

     ONLINE_DBCP

     SHORT

     SERVICE_TIME

     DBCP

     ONLINE_UCP

     SHORT

     SERVICE_TIME

     UCP


    서비스 생성

    srvctl add service -db ORA12C -service LONG_SRV -preferred ORA12C1,ORA12C2 \
    -clbgoal LONG -notification true
    srvctl add service -db ORA12C -service SHORT_SRV -preferred ORA12C1,ORA12C2 \
    -clbgoal SHORT -rlbgoal NONE
    srvctl add service -db ORA12C -service ONLINE_DBCP -preferred ORA12C1,ORA12C2 \
    -clbgoal SHORT -rlbgoal SERVICE_TIME
    srvctl add service -db ORA12C -service ONLINE_UCP -preferred ORA12C1,ORA12C2 \
    -clbgoal SHORT -rlbgoal SERVICE_TIME



    Note
    RLB_GOAL이 THROUGHPUT인 경우는 테스트 대상에서 제외했습니다. 제 테스트 환경에서는 RLB_GOAL이 SERVICE_TIME인 경우와 THROUGHPUT인 경우의 차이점을 발견하지 못했기 때문입니다. 약간의 차이는 있지만, 두 개의 옵션 모두 "Call당 처리 시간" 기준으로 커넥션이 이전되었습니다.


    서비스 시작

    srvctl start service -db ORA12C -service LONG_SRV
    srvctl start service -db ORA12C -service SHORT_SRV
    srvctl start service -db ORA12C -service ONLINE_DBCP
    srvctl start service -db ORA12C -service ONLINE_UCP


    서비스 확인

    srvctl status service -db ORA12C

    Service LONG_SRV is running on instance(s) ORA12C1,ORA12C2
    Service ONLINE_DBCP is running on instance(s) ORA12C1,ORA12C2
    Service ONLINE_UCP is running on instance(s) ORA12C1,ORA12C2
    Service SHORT_SRV is running on instance(s) ORA12C1,ORA12C2



    10-3. 로드 밸런싱과 관련된 MMON, MMNL, LREG, 리스너 동작 방식


    몇 가지 테스트를 통해 분석한 MMON, MMNL, LREG, 리스너의 동작 방식은 다음과 같습니다. (그림-1. 참조)

    1. MMON은 30초에 1번씩 RLB로 설정된 서비스들의 서비스 매트릭스 정보를 SYS.SYS$SERVICE_METRICS_TAB에 저장합니다.
    2. 각 노드의 MMNL은 5초에 1번씩 모든 서비스들의 서비스 매트릭스 정보를 V$SERVICEMETRIC에 저장합니다.
    3. LREG (11g까지는 PMON)는 서비스 매트릭스 정보를 리스너들에게 전달합니다.
    4. 리스너들은 LREG로부터 서비스 메트릭스 정보를 전달 받습니다.


    그림-1. 서비스 매트릭스 전달 방식



    10-4. 검증 방법 상세


    사실, 이 부분은 엔지니어 적인 호기심으로 트레이싱을 해본 내용들입니다. 그냥 스킵해도 무방하며, 트레이스 방법에 대해서만 가볍게 리뷰하셔도 좋을 것 같습니다.



    10-3의 1번 항목 검증


    select to_char(ENQ_TIME, 'YYYY-MM-DD: HH:MI:SS') Enq_time, user_data
    from   SYS.SYS$SERVICE_METRICS_TAB
    order  by 1;

    2016-07-08: 09:45:11  SYS$RLBTYP('ONLINE_UCP', 'VERSION=1.0 database=ORA12C servic
                          e=ONLINE_UCP { {instance=ORA12C1 percent=100 flag=UNKNOWN af
                          f=FALSE} } timestamp=2016-07-08 18:45:11')
    2016-07-08: 09:45:11  SYS$RLBTYP('ONLINE_DBCP', 'VERSION=1.0 database=ORA12C servi
                          ce=ONLINE_DBCP { {instance=ORA12C1 percent=100 flag=UNKNOWN
                          aff=FALSE} } timestamp=2016-07-08 18:45:11')
    2016-07-08: 09:45:41  SYS$RLBTYP('ONLINE_UCP', 'VERSION=1.0 database=ORA12C servic
                          e=ONLINE_UCP { {instance=ORA12C1 percent=100 flag=UNKNOWN af
                          f=FALSE} } timestamp=2016-07-08 18:45:41')
    2016-07-08: 09:45:41  SYS$RLBTYP('ONLINE_DBCP', 'VERSION=1.0 database=ORA12C servi
                          ce=ONLINE_DBCP { {instance=ORA12C1 percent=100 flag=UNKNOWN
                          aff=FALSE} } timestamp=2016-07-08 18:45:41')


    Note
    SYS$SERVICE_METRICS_TAB 테이블에는 RLB와 관련된 서비스의 서비스 메트릭스 정보만 30초마다 저장됩니다. 해당 테이블에는 CLB 관련 서비스의 정보는 저장되지 않습니다.


    다음과 같이, kill -stop 명령어로 MMON 프로세스를 STOP 시킨 후에는 SYS$SERVICE_METRICS_TAB 테이블에 서비스 매트릭스 정보가 입력되지 않는 것을 알 수 있습니다.

    [oracle@rac2 SS]$ ps -ef | grep mmon
    oracle    8474     1  0 18:43 ?        00:00:01 ora_mmon_ORA12C2
    [oracle@rac2 SS]$ kill -stop 8474
    [oracle@rac2 SS]$ su root
    [root@rac2 SS]# strace -p 8474
    Process 8474 attached
    --- stopped by SIGSTOP ---



    10-3의 2번 항목 검증


    1번과 동일한 방법으로 MMNL 프로세스를 STOP 시키면 V$SERVICEMETRIC 테이블에 서비스 매트릭스 정보가 입력되지 않는 것을 알 수 있습니다. 
     

    10-3의 3번 항목 검증


    10257 트레이스를 이용하면 됩니다. 해당 트레이스를 활성화시키면 PMON 및 LREG의 수행 내용을 확인할 수 있습니다. SQL> alter system set events '10257 trace name context forever, level 16'; --트레이스 on
    SQL> alter system set events '10257 trace name context off'; -- 트레이스 off


    예시-1. LREG 프로세스 트레이스 결과

    *** 2016-07-08 19:13:34.357
    kmlwait: status: succ=4, wait=0, fail=0
    kmmlrl: update for process drop delta: 107 106 72 74 299
    kmmlrl: 72 processes
    kmmlrl: node load 445
    kmmlrl: instance load 4
    kmmgdnu: LONG_SRV
             goodness=0, delta=1, pdb=1,
             flags=0x104:unblocked/not overloaded, update=0x6:G/D/-
    kmmgdnu: ONLINE_DBCP
             goodness=100, delta=100, pdb=1,
             flags=0x104:unblocked/not overloaded, update=0x6:G/D/-
    kmmgdnu: ONLINE_UCP
             goodness=100, delta=100, pdb=1,
             flags=0x104:unblocked/not overloaded, update=0x6:G/D/-
    kmmgdnu: SHORT_SRV
             goodness=0, delta=100, pdb=1,
             flags=0x104:unblocked/not overloaded, update=0x6:G/D/-
    kmmgdnu: ORA12CXDB
             goodness=0, delta=1, pdb=0,
             flags=0x105:unblocked/not overloaded, update=0x6:G/D/-
    kmmgdnu: ORA12C
             goodness=0, delta=1, pdb=0,
             flags=0x104:unblocked/not overloaded, update=0x6:G/D/-



    10-3의 4번 항목 검증


    리스너 트레이스를 이용하면 됩니다.
    • 로컬 리스너 트레이스 방법: lsnrctl trace user
    • 스캔 리스너 트레이스 방법: lsnrctl trace user LISTENER_SCAN1

    예시-2. 리스너 프로세스 트레이스 결과 
    2016-07-08 19:13:34.358201 : nsglgrDoRegister:service:ONLINE_UCP what:4 value:100
    2016-07-08 19:13:34.358209 : nsglgrDoRegister:service:ONLINE_UCP what:2 value:100
    2016-07-08 19:13:34.358216 : nsglgrDoRegister:service:ONLINE_DBCP what:4 value:100
    2016-07-08 19:13:34.358223 : nsglgrDoRegister:service:ONLINE_DBCP what:2 value:100
    2016-07-08 19:13:34.358230 : nsglgrDoRegister:service:SHORT_SRV what:4 value:100
    2016-07-08 19:13:34.358237 : nsglgrDoRegister:service:SHORT_SRV what:2 value:0
    2016-07-08 19:13:34.358245 : nsglgrDoRegister:service:LONG_SRV what:4 value:1
    2016-07-08 19:13:34.358253 : nsglgrDoRegister:service:LONG_SRV what:2 value:0
    2016-07-08 19:13:34.358261 : nsglgrDoRegister:service:ORA12C what:4 value:1
    2016-07-08 19:13:34.358269 : nsglgrDoRegister:service:ORA12C what:2 value:0


    Note
    두 개의 트레이스 파일을 비교함으로써 리스너 프로세스의 what:4=delta, what:2=goodness 임을 알 수 있습니다. 해당 값들은 V$SERVICEMETRIC의 DELTA 및 GOODNESS 칼럼 값과 동일합니다.



    참고 문헌


    http://www.slideshare.net/fullscreen/alexgorbachev/demistifying-oracle-rac-workload-management-by-alex-gorbachev-nocoug-2010-spring-conference/1


    글을 마치며


    이번 시간에는 RLB, CLB 서비스 생성 방법 및 로드 밸런싱을 위한 "서비스 매트릭스" 정보들이 흐름을 살펴보았습니다.


    [11] 톰캣 서버에 UCP (Universal Connection Pool) 구성 및 JSP 샘플 코드 작성 바로가기


    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    똘똘님. 자동으로 로드를 분산시킨다는 개념은 위험성이 내포되어 있긴 하지만, 원리를 잘 이해하고 적용한다면 관리 측면에서는 상당히 매력적인 기능인 것 같습니다. 공부를 하다 보니 CLB, RLB, CLB_GOAL, RLB_GOAL 등의 용어가 등장합니다. CLB의 개념은 그다지 어렵지 않은데, RLB 개념이 명확하지 않습니다. CLB와 RLB의 개념을 정립해주실 수 있을까요?




    네. 간단한 질문이지만 상당히 어려운 질문입니다. 설명드릴 것이 많지만, 한번에 너무 많은 지식은 소화하기 힘드니 이번 시간에는 CLB와 RLB의 차이를 명확히 아는 것만을 목표로 진행해 보겠습니다.



    들어가기에 앞서


    로드 밸런싱 관련 내용은 설명할 내용이 많은 관계로 다음과 같이 4개의 연재로 진행할 예정입니다.


    1) [09] Connection Load Balancing (CLB)과 Runtime Connection Load Balancing (RLB) 설명

    2) [10] CLB, RLB를 위한 서비스 매트릭스 정보의 흐름

    3) [11] 톰캣 서버에 UCP (Universal Connection Pool) 구성 및 JSP 샘플 코드 작성

    4) [12] Jmeter + 톰캣 + UCP를 이용한 RLB (Runtime Load Balancing) 동작 방식 검증



    9-1. 로드 밸런싱 개요


    클러스터 환경에서 동시에 다수의 노드가 동일한 서비스를 수행하는 경우, 바꿔 말해 하나의 서비스가 여러 개의 노드에서 동시에 수행되는 환경이 있다고 가정해보겠습니다. 이때, 서비스 성능 수준을 높이기 위해서 로드 밸런싱은 반드시 필요한 요소입니다. 일반적으로 로드 밸런싱은 2가지로 구분할 수 있습니다.

    • 커넥션 로드 밸런싱
    • 런-타임 로드 밸런싱
    Note
    커넥션 로드 밸런싱은 "세션 수" 또는 "CPU 사용률(%)"을 기준으로 동작하고, 런-타임 로드 밸런싱은 "서비스 처리 시간"을 기준으로 동작합니다.



    커넥션 로드 밸런싱의 한계점

    • 커넥션 시점에는 CPU 사용률(%)이 비슷했으나, 접속한 노드의 CPU(%)이 갑자기 높아지는 경우
    • 세션 수나 CPU 사용률(%)은 비슷하나, 노드 간의 서비스 처리 성능이 차이가 나는 경우  
    이러한 문제를 해결하기 위해 "런-타임 로드 밸런싱"이 필요하다고 할 수 있습니다.



    9-2. 오라클의 로드 밸런싱 방법


    오라클은 커넥션 로드 밸런싱과 런-타임 로드 밸런싱을 모두 제공합니다. (표-1 및 그림-1 참조)
    • 커넥션 로드 밸런싱: Connection Load Balancing (CLB)이라고 하며, CLB_GOAL로 설정
    • 런-타임 밸런싱: Runtime Load Balancing (RLB)이라고 하며, RLB_GOAL로 설정 


    그림-1. 로드 밸런싱 옵션


    Note
    RLB_GOAL을 설정하기 위해서는 CLB_GOAL을 SHORT로 지정해야 합니다.


    표-1. CLB, RLB 비교 설명

     구분

     CLB (커넥션 로드 밸런싱)

     RLB (런-타임 로드 밸런싱)

     설정 방법

     서비스 생성 시, CLB_GOAL 설정

     서비스 생성 시, RLB_GOAL 설정

     옵션

     LONG
     "세션 수"가 적은 노드로 접속

     SERVICE_TIME
     UCP 사용 시, 서비스 처리 시간이 우수한 노드로 접속

     (OLTP 환경에 적합)

     SHORT
     "CPU(%)"이 낮은 노드로 접속

     THROUPUT
     UCP 사용 시, 서비스 처리 능력이 우수한 노드로 접속
     (BATCH 환경에 적합)


    Note
    LONG 옵션에서 말하는 "세션 수"는 "해당 서비스로 접속한 세션 수"를 의미합니다. 전체 세션 수가 아닌 점을 주의해야 합니다. 



    9-3. RLB는 모든 환경에서 적용될까요?


    "표-1"에서 언급한 것처럼 "RLB는 UCP (Unified Connection Pool) 환경에서만 동작"합니다. 간단하지만 가장 중요한 내용이라고 할 수 있겠습니다. DBCP, JDBC Connection Pool 및 SQL*Plus와 같은 클라이언트의 접속은 RLB가 적용되지 않습니다. 테스트 시, 모니터링을 해보면 DBCP나 SQL*Plus 접속에 대해서도 RBL가 적용되는 것 같은 착각을 할 수 있지만, 해당 접속들은 CLB로만 처리됩니다.

     

     



    참고 문헌


    http://oracleinaction.com/rac-load-balancing/



    [10] CLB, RLB 동작을 위한 서비스 매트릭스 정보의 흐름 바로가기

    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    똘똘님. 지난 포스팅에서 정리해주신 서비스 별 성능 통계를 제공해주는 다양한 뷰에 대해서 학습 중입니다. 다른 뷰들은 대부분 쉽게 이해가 되는데요. V$SERVICEMETRIC 뷰와 V$SERVICEMETRIC_HISTORY 뷰의 차이를 정확히 모르겠습니다. 그리고 CALLSPERSEC 칼럼의 수치가 실제 실행 횟수보다 크게 나오는 것 같습니다. 이에 대한 설명을 부탁드려도 될까요?



    네. 공부할수록 궁금한 게 많아지는건 아주 당연하고도 좋은 현상입니다. 그럼 시작해볼까요?




    8-1. V$SERVICEMETRIC 뷰와 V$SERVICEMETRIC_HISTORY 뷰의 차이점


    뷰의 이름만으로 보면, 하나는 현재 데이터를 제공하고 다른 하나는 이력 데이터를 제공한다는 점은 쉽게 인지할 수 있으나, 조금 더 중요한 차이점이 있습니다. V$SERVICEMETRIC 뷰는 런타임 로드 밸런싱을 위해 사용되고, V$SERVICEMETRIC_HISTORY 뷰는 서비스 별 성능 관리를 위해 사용되다는 점입니다. (표-1 참조) [런타임 로드 밸런싱에 대해서는 별도 포스팅 예정입니다]


    표-1. V$SERVICEMETRIC 뷰와 V$SERVICEMETRIC_HISTORY 뷰 비교

     

      V$SERVICEMETRIC

     V$SERVICEMETRIC_HISTORY

     주요 목적

     런타임 로드 밸런싱

     (RLB - Runtime Load Balancing)

     서비스 별 성능 관리

     RLB용 칼럼

     GOODNESS

     없음

     제공 데이터

     서비스 별로 2개의 성능 통계를 제공

     (1개는 최근 5초, 1개는 최근 1분)

     서비스 별로 5초 단위의 성능 통계 이력 (최근 2분) 및 1분 단위의 성능 통계 이력 (최근 1시간) 제공



    8-2. 각 뷰에서 제공하는 성능 통계 데이터 구간


    "표-1"에서는 최근 5초, 최근 1분이라고 기술했으나, 보다 정확한 구간은 "그림-1"과 같습니다.


    그림-1. 각 뷰에서 제공하는 성능 통계 데이터 구간 설명



    8-3. DBTIMEPERSEC 칼럼 시간 단위


    대부분의 칼럼들은 매뉴얼에 정확히 기재되어 있으나 DBTIMEPERSEC 칼럼은 단위가 기재되어 있지 않습니다. 해당 칼럼의 단위는 1/100초 입니다 (참고로, 시간 관련 칼럼들의 단위를 "표-2"에 기술해 두었습니다)


    표-2. 칼럼 별 시간 단위

     칼럼명 

     단위 

     INTSIZE_CSEC

     centi-Second (1/100초)

     ELAPSEDPERCALL

     micro-Second (1/1,000,000초)

     CPUPERCALL

     micro-Second (1/1,000,000초)

     DBTIMEPERCALL

     micro-Second (1/1,000,000초)

     DBTIMEPERSEC

     centi-Second (1/100초)



    8-4. CALLSPERSEC 칼럼의 이해


    매뉴얼에 보면 CALLSPERSEC 칼럼의 설명은 "Number of user calls per second", 즉, 초당 발생한 "user calls"라고 명시되어 있습니다. 다시 말해, 해당 칼럼에서 제공하는 수치는 SQL의 실행 횟수가 아닌 "user calls"라는 점을 주의해야 합니다. "user calls"는 아래와 같은 3가지 유형의 콜의 횟수를 합한 수치를 제공합니다.


    1. PARSE call
    2. EXEC call
    3. FETCH call

    예를 들어, 1건을 fetch하는 SQL을 수행하면 3개의 call (각 단계별 1회)이 발생합니다. 만일, fetch 해야할 레코드가 많다면 그만큼 많은 FETCH call이 발생하게 됩니다. 예를 들어 설명하겠습니다. ONLINE_SRV 서비스에 속하는 online1.jsp는 1000건을 fetch하는 SQL을 수행합니다. 이때, ONLINE_SRV의 CALLSPERSEC 수치는 얼마일까요?

    예시-1. online1.jsp 예제
    <%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%>
    <%@ page import="java.sql.*"%>
    <%@ page import="javax.naming.*"%>
    <%@ page import="javax.sql.*"%>
    <html>
    <head>
    <body >
    <%
            Integer v1 = null;
            Connection conn=null;
            Statement st=null;
            ResultSet rs=null;
            try {
                    Context initContext = new InitialContext();
                    Context envContext  = (Context) initContext.lookup("java:/comp/env");
                    DataSource datasource = (DataSource) envContext.lookup("jdbc/onlinesrv");
                    conn = datasource.getConnection();
                    st=conn.createStatement();
                    String sql = "select c1 from t1 where rownum<=1000";
                    rs = st.executeQuery(sql);
                    while (rs.next()) {
                        v1 = rs.getInt(1);
    %>
                        <%=v1 %>
    <%
                    }
            } catch (Exception e){
                    e.printStackTrace(System.out);
            }
            finally {
                    st.close();
                    rs.close();
                    conn.close();
            }
    %>
    </body>
    </html>


    예시-2. online1.jsp를 수행한 후에 V$SERVICEMETRIC 뷰 조회
    select to_char(begin_time,'HH24:MI:SS') begin_time,
           to_char(end_time, 'HH24:MI:SS') end_time,
           intsize_csec interval,
           round(callspersec*intsize_csec/100,1) calls_in_interval, -- 구간동안 발생한 횟수
           callspersec -- 초당 발생 횟수
    from   v$servicemetric
    where  service_name='ONLINE_SRV';

    BEGIN_TI END_TIME   INTERVAL CALLS_IN_INTERVAL CALLSPERSEC
    -------- -------- ---------- ----------------- -----------
    12:12:22 12:12:27        500               102        20.4


    Note
    CALLSPERSEC 칼럼 값은 초당 값 (Value/Sec)이므로, 구간 사이에 발생한 값 (Delta)으로 환산해서 설명하도록 하겠습니다. 조회 결과를 보면, CALLS_IN_INTERVAL 칼럼 값은 102입니다. 예상과 다르죠? 102인 이유는 PARSE call 1회, EXEC call 1회, FETCH call 100회를 수행했기 때문입니다. 또한, 1000건을 fetch하는데 FETCH call이 100회인 이유는 JDBC가 기본적으로 10개씩 레코드를 fetch(배열 크기=10)하기 때문입니다. 그렇다면 배열 크기를 증가시키면 CALLSPERSEC 칼럼 값에 변화가 있을까요?


    8-5. Array 크기 변경 후 CALLSPERSEC 값의 변화 확인


    setFetchSize 함수를 이용해서 배열 크기를 증가시킨 후 테스트를 수행해보겠습니다.


    예시-3. 배열 크기 증가
    st=conn.createStatement();
    st.setFetchSize(100);


    예시-4. 수행 결과 확인
    select to_char(begin_time,'HH24:MI:SS') begin_time,
           to_char(end_time, 'HH24:MI:SS') end_time,
           intsize_csec interval,
           round(callspersec*intsize_csec/100,1) calls_in_interval, -- 구간동안 발생한 횟수
           callspersec -- 초당 발생 횟수
    from   v$servicemetric
    where  service_name='ONLINE_SRV';
    BEGIN_TI END_TIME   INTERVAL CALLS_IN_INTERVAL CALLSPERSEC
    -------- -------- ---------- ----------------- -----------
    12:13:02 12:13:07        500                12         2.4


    조회 결과를 보면, CALLS_IN_INTERVAL 칼럼 값이 12로 변경된 것을 알 수 있습니다. 즉, 배열 크기 증가에 따라 Fetch Call수가 100회에서 10회로 줄어든 것이 반영된 결과입니다.


    8-6. 글을 마치며


    서비스 별 응답 시간, CPU 사용 시간 및 Call 횟수를 분석하는데 있어서 V$SERVICEMETRIC_HISTORY 뷰는 아주 유용한 데이터를 제공합니다. 실시간 데이터와 함께 최근 1시간의 데이터를 제공하므로, 성능 이력 또한 분석할 수 있다는 장점을 가지고 있습니다. 따라서, 서비스 별 성능 분석 시에 매우 유용하게 활용할 수 있을 것입니다.





    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    똘똘님 덕분에 톰캣 환경에서의 DBCP JDBC Connection Pool 구성은 쉽게 마무리했습니다. (이전 포스팅 참조) 새로운 미션은 커넥션 풀 별로 성능 현황을 모니터링하고 이력을 분석하는 것입니다. V$SESSION 뷰를 확인해보니 2개의 서비스 모두 PROGRAM 명은 'JDBC Thin Client'로 표시되고 SERVICE 명은 'SYS$USERS'로 표시되므로 구분이 되지 않습니다. DBMS_APPLICATION_INFO.SET_MODULE 패키지를 이용하면 "MODULE" 및 "ACTION" 설정이 가능하다고 알고 있습니다만, 소스 수정이 불가능한 상황입니다. 어떻게 하면 될까요?



    오라클 서비스를 이용하면 아주 쉽게 이 문제를 풀 수 있습니다. 그럼 시작해볼까요?





    7-1. 서비스 생성 및 시작


    DB 서버에 로그인 한 후, 커넥션 풀을 위한 2개의 서비스를 생성한 후 서비스를 시작합니다. (테스트 환경은 "누구나 쉽게 따라할 수 있는 Oracle 12c RAC 설치 가이드" 참조)


    SRVCTL을 이용한 서비스 생성

    srvctl add service -d ORA12C -service ONLINE_SRV -preferred ORA12C1 -available ORA12C2 -failovermethod BASIC
    srvctl add service -d ORA12C -service BATCH_SRV  -preferred ORA12C2 -available ORA12C1 -failovermethod BASIC


    서비스 시작

    srvctl start service -d ORA12C -s ONLINE_SRV
    srvctl start service -d ORA12C -s BATCH_SRV


    서비스 확인

    srvctl status service -d ORA12C
    Service BATCH_SRV  is running on instance(s) ORA12C2
    Service ONLINE_SRV is running on instance(s) ORA12C1


    Note
    싱글 인스턴스에서 테스트를 하는 경우에는 DBMS_SERVICE 패키지를 이용해서 서비스를 생성하면 됩니다.



    7-2. 커넥션 풀 별로 context.xml 파일 내의 url 변경


    새로운 서비스로 접속할 수 있도록 context.xml 파일 내의 url을 변경합니다.


    예시-1. 온라인 서비스용 url 변경 (/usr/local/tomcat/webapps/online/META-INF/context.xml)

    <?xml version='1.0' encoding='utf-8'?>
    <Context>
        <WatchedResource>WEB-INF/web.xml</WatchedResource>
        <Manager pathname="" />
        <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
            <Resource
            name="jdbc/onlinesrv"
            auth="Container"
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            driverClassName="oracle.jdbc.OracleDriver"
            url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(FAILOVER=ON)
                 (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.56.81)(PORT=1521))
                 (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.56.82)(PORT=1521)))
                 (CONNECT_DATA=(SERVICE_NAME=ONLINE_SRV)(FAILOVER_MODE=(METHOD=BASIC))))"
            username="apps"
            password="apps"
            maxActive="20"
            maxIdle="10"
            initialSize="10"
            connectionPoolName="onlinesrv_pool"
            maxWait="-1"/>
    </Context>


    예시-2. 배치 서비스용 url 변경 (/usr/local/tomcat/webapps/batch/META-INF/context.xml)

    <?xml version='1.0' encoding='utf-8'?>
    <Context>
        <WatchedResource>WEB-INF/web.xml</WatchedResource>
        <Manager pathname="" />
        <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
            <Resource
            name="jdbc/batchsrv"
            auth="Container"
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            driverClassName="oracle.jdbc.OracleDriver"
            url="jdbc:oracle:thin:@(DESCRIPTION=(ADDRESS_LIST=(FAILOVER=ON)
                 (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.56.82)(PORT=1521))
                 (ADDRESS=(PROTOCOL=TCP)(HOST=192.168.56.81)(PORT=1521)))
                 (CONNECT_DATA=(SERVICE_NAME=BATCH_SRV)(FAILOVER_MODE=(METHOD=BASIC))))"
            username="apps"
            password="apps"
            maxActive="20"
            maxIdle="10"
            initialSize="10"
            connectionPoolName="batchsrv_pool"
            maxWait="-1"/>
    </Context>



    7-3. 톰캣 재 시작 후 V$SESSION 뷰 확인


    context.xml 설정이 완료된 후에는 톰캣을 재 시작합니다.


    service tomcat stop
    service tomcat start


    V$SESSION 뷰를 확인해보겠습니다.


    select inst_id, program, service_name from gv$session where program like 'JDBC%' order by 1;


       INST_ID PROGRAM                        SERVICE_NAME
    ---------- ------------------------------ ----------------------------------
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             1 JDBC Thin Client               ONLINE_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV
             2 JDBC Thin Client               BATCH_SRV


    결과에서 보듯이, 서비스 설정 후에는 service_name 칼럼에 각각의 "서비스명"이 출력되는 것을 알 수 있습니다. 즉, 이를 통해 세션 레벨에서의 서비스 구분이 가능한 것을 알 수 있습니다. 그렇다면 서비스 별로 다양한 성능 통계 정보는 어떻게 확인할 수 있을까요?



    7-4. 서비스 별 성능 통계 정보를 제공하는 다양한 뷰들


    오라클은 V$SESSION.SERVICE_NAME 이외에도 서비스 별로 다양한 성능 통계 정보를 제공하는 뷰들을 제공하고 있습니다. 이러한 뷰들을 이용하면 서비스 별 세션 뿐 아니라 SQL, 대기이벤트, 성능통계 및 대기 클래스등의 다양한 성능 정보를 확인할 수 있습니다.


    • V$SQL : SERVICE 칼럼을 통해 서비스 별 SQL 성능 통계 확인 가능
    • V$SERVICEMETRIC : 서비스 별로 2개의 성능 통계를 제공 (1개는 최근 5초, 1개는 최근 1분)
    • V$SERVICEMETRIC_HISTORY : 서비스 별로 5초 단위의 성능 통계 이력 (최근 2분) 및 1분 단위의 성능 통계 이력 (최근 1시간) 제공
    • V$SERVICE_EVENT : 서비스 별로 대기이벤트 정보 제공
    • V$SERVICE_STATS : 서비스 별로 성능통계 정보 제공 (AWR로도 제공: DBA_HIST_SERVICE_STAT)
    • V$SERVICE_WAIT_CLASS : 서비스 별로 대기클래스 정보 제공 (AWR로도 제공: DBA_HIST_SERVICE_WAIT_CLASS)  
       

    글을 마치며


    서비스 별 성능 통계를 제공하는 뷰중에서 V$SERVICEMETRICV$SERVICEMETRIC_HISTORY 뷰는 조금 더 학습이 필요할 것 같습니다. 다음 포스팅은 해당 뷰들에서 제공하는 데이터의 내용을 분석할 예정입니다.


    [08] V$SERVICEMETRIC, V$SERVICEMETRIC_HISTORY 뷰를 이용한 서비스 성능관리 방안 으로바로가기



    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License

    안녕하세요. 똘똘님! 이번 미션은 톰캣 JDBC Connection Pool을 설정하는 것입니다. 커넥션 풀을 이용해보기는 했지만, 제가 직접 구성을 하려니 막막합니다. 톰캣 7 설치, JDK 1.7 설치까지는 쉽게 했지만, 커넥션 풀을 설정하는 부분에서 헤매고 있습니다. 구글링을 해보면 Server.xml, Context.xml, Web.xml 등 환경 파일 내에 설정 정보를 넣어주면 쉽게 된다고 하는데, 잘 되지 않습니다. 그리고 커넥션 풀을 이용한 JSP 샘플 코드를 작성해보고 싶은데, 이 역시 쉽지 않습니다. 알려주세요. 똘똘님!



    제가 WAS 전문가는 아니지만, 말씀하신 부분은 도움을 드릴 수 있을 것 같습니다. 그럼 시작해볼까요?



    6-1. 개요


     
    DB Connection Pool (이하 DBCP)톰캣 JDBC Connection Pool을 설정하는 방법은 아주 간단합니다. context.xml 파일에만 적절한 정보를 입력하면 됩니다. 아주 쉽죠? 그럼, 온라인 서비스와 배치 서비스 각각을 위한 커넥션 풀을 설정하는 예제를 통해서 설명하도록 하겠습니다.


    Note
    참고로, 톰캣 6부터는 web.xml 파일에 <resource-ref> 항목을 등록하지 않아도 됩니다.

     


    6-2. 서비스를 위한 디렉토리 생성



    cd /usr/local/tomcat  -- 설치 디렉토리로 이동
    cd webapps
    mkdir -p online/META-INF
    mkdir -p batch/META-INF



    6-3. 각 서비스의 META-INF 디렉토리 내에 context.xml 생성



    예시-1. /usr/local/tomcat/webapps/online/META-INF/context.xml 내용

    <?xml version='1.0' encoding='utf-8'?>
    <Context>

        <WatchedResource>WEB-INF/web.xml</WatchedResource>
        <Manager pathname="" />
        <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
     
     <Resource
            name="jdbc/onlinesrv"
            auth="Container"
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            driverClassName="oracle.jdbc.OracleDriver"
            url="jdbc:oracle:thin:@192.168.56.81:1521:ORA12C1"
            username="apps"
            password="apps"
            maxActive="20"
            maxIdle="10"
            initialSize="10"
            connectionPoolName="onlinesrv_pool"
            maxWait="-1"/>
     
    </Context>


    예시-2. /usr/local/tomcat/webapps/batch/META-INF/context.xml 내용

    <?xml version='1.0' encoding='utf-8'?>
    <Context>

        <WatchedResource>WEB-INF/web.xml</WatchedResource>
        <Manager pathname="" />
        <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" />
     
     <Resource
            name="jdbc/batchsrv"
            auth="Container"
            type="javax.sql.DataSource"
            factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
            driverClassName="oracle.jdbc.OracleDriver"
            url="jdbc:oracle:thin:@192.168.56.82:1521:ORA12C2"
            username="apps"
            password="apps"
            maxActive="20"
            maxIdle="10"
            initialSize="10"
            connectionPoolName="batchsrv_pool"
            maxWait="-1"/>
     
    </Context>


    Note
    오라클 11g부터는 사용자 비밀번호의 대소문자를 구별합니다. 따라서, 대소문자를 구별해서 정확한 비밀번호를 password 항목을 입력하도록 합니다. 참고로, 비밀번호 대소문자를 구별하지 않으려면 sec_case_sensitive_logon 파라미터를 false로 변경하면 됩니다.



    6.4 톰캣 서버 재시작 후 DB 서버에서 커넥션 풀 접속 확인




    service tomcat stop
    service tomcat start


    Note
    톰캣 서버를 service 방식으로 start/stop 하는 방법은 "여기"를 참고하세요.


    select inst_id, username, to_char(logon_time,'YYYY:MM:DD HH24/MI/SS') logontime , program, service_name
    from gv$session
    where username='APPS'
    and program like 'JDBC%'
    order by 1,3;


       INST_ID USERNAME   LOGONTIME            PROGRAM            SERVICE_NAME
    ---------- ---------- -------------------- ------------------ ---------------
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             1 APPS       2016:06:28 15/52/25  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS
             2 APPS       2016:06:28 15/52/23  JDBC Thin Client   SYS$USERS


    Note
    initialSize를 10으로 설정했으므로, RAC 1,2번 노드 각각 10개의 세션이 연결된 것을 확인할 수 있습니다.



    6.5 샘플 JSP 코드 작성



    DBCP커넥션 풀이 생성된 상태이므로, 커넥션 풀의 커넥션 객체를 이용해서 DB에 접속하는 JSP 샘플 코드를 작성해보도록 하겠습니다.


    예시-3. /usr/local/tomcat/webapps/online/test.jsp의 내용

    <%@ page language="java" contentType="text/html; charset=UTF-8"  pageEncoding="UTF-8"%>
    <%@ page import="java.sql.*"%>
    <%@ page import="javax.naming.*"%>
    <%@ page import="javax.sql.*"%>
    <html>
    <head>
    <body >
    <%
            String v1 = null;

            try {
                    Context initContext = new InitialContext();
                    Context envContext  = (Context) initContext.lookup("java:/comp/env");
                    DataSource datasource = (DataSource) envContext.lookup("jdbc/onlinesrv");
                    Connection conn = datasource.getConnection();

                    Statement st=conn.createStatement();
                    String sql = "select 'Welcome! Tomcat DB Connection Pool (DBCP)' from dual";
                    ResultSet rs = st.executeQuery(sql);
                    rs.next();
                    v1 = rs.getString(1);
            } catch (Exception e){
                    e.printStackTrace(System.out);
            }
    %>
            <%=v1 %>

    </body>
    </html>


    Note
    샘플 코드에서 가장 중요한 부분은 envContext.lookup 부분에 context.xml 에 설정한 name을 입력한다는 것입니다. 예를 들어, 온라인 서비스 커넥션 풀 객체를 이용하려면 "jdbc/onlinesrv"를 입력하면 되고 배치 서비스 커넥션 풀 객체를 이용하려면 "jdbc/batchsrv"를 입력하면 됩니다.


    웹 브라우저를 이용해서 샘플 JSP를 실행하면 다음과 같은 결과를 확인할 수 있습니다.




    똘똘님 덕분에 DBCP 커넥션 풀 구성 및 JSP 샘플 코드 작성을  쉽게 완료했습니다. :)



    네. 궁금님. 그럼 다음 시간에는 DBCP 커넥션 풀 환경에서 "서비스"를 이용한 성능 관리에 대해서 살펴보도록 하겠습니다.



    저작자 표시 비영리 변경 금지
    신고
    크리에이티브 커먼즈 라이선스
    Creative Commons License
    TAG DBCP, 톰캣


     

    티스토리 툴바