My Books

My Slides

rss 아이콘 이미지

[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


 

티스토리 툴바