Oracle9i Real Application Clusters의페일오버기능- CTF vs TAF
아마도 독자들이 Oracle9i Real Application Clusters를 도입하는 가장 큰
이유는 Oracle9i Real Application Clusters가 고가용성(HA)을 보장해 주
기때문일것인데, 실제로HA를구현하기위해서가장중요한부분이애플리
케이션 페일오버(application failover)이다. 애플리케이션 페일오버를 간
단히설명하면, Oracle9i Real Application Clusters 환경에서하나의노드
에장애가발생했을때애플리케이션은나머지살아있는노드들중의하나로
부터서비스를받게되므로, 엔드유저들은장애가발생했는지조차모르는것
이다. 이것이바로오라클에서Oracle9i Real Application Clusters를‘난공
불락(Unbreakable)’이라고내세우는이유이다.
최근에는HA에 대한 관심이 높아지면서 플랫폼 벤더에서도 여러 가지
HA 솔루션 - 이를테면, IP 스위치오버 - 을 제공한다. Oracle9i Real
Application Clusters 사용 고객이 이러한 플랫폼 솔루션을 훌륭하게 함께
사용하는경우도많이있지만, 이번호에서는혼돈을피하기위해100% 오라
클이제공하는솔루션만을다루도록한다.
Oracle9i Real Application Clusters에서제공하는페일오버기능에는
CTF(Connection Time Failover)와 TAF(Transparent Application
Failover)가있다. 이두가지기능모두는Oracle8i Parallel Server에서부터
제공되던 기능이다. 그런데, 많은 고객들이CTF와TAF가 상호 배타적인 기
능이라고여기는것같은데, TAF는CTF 기능위의부가적인기능이다. 따라
서, CTF를사용할것인지TAF를사용할것인지고민할필요없이TAF를사용
할것인지아닌지의여부만선택하면된다.
이글의기반이되는필자의테스트환경은다음과같다. 앞으로이어지
는테스트에서는항상이전의설정을기본으로변경사항만추가하도록하
겠다.
. 데이타베이스서버 >>> 2노드의Oracle9i Real Application Clusters
. 운영체제: Sun Solaris 8
. 오라클데이타베이스버전: Oracle9i Database Release 2(9.2.0.3) 64비트
. 호스트명(공용네트워크) : krrac1, krrac2
. ORACLE_SID : RAC1(krrac1), RAC2(krrac2)
. init.ora 파라미터
local_listener=(지정 안함)
remote_listener=(지정 안함)
service_names=(지정 안함)
db_name='rac'
rac1.instance_name='rac1'
rac2.instance_name='rac2'
. listener.ora(krrac1. krrac2는 HOST와 SID_NAME만 각각 krrac2,
RAC2이며나머지는동일)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = krrac1)
(PORT = 1521))
)
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(ORACLE_HOME = /data/oracle)
(SID_NAME = RAC1)
)
)
. Oracle*Net 클라이언트(SQL*Plus)
. 운영체제 : Windows 2000 Professional
. 오라클클라이언트버전 : Oracle9i Database Release 2(9.2.0.3)
. tnsnames.ora
RAC1 =
(description=
(address=(protocol=tcp)(host=krrac1)(port=1521))
(connect_data=
(service_name=RAC))
)
자, 이제클라이언트에서rac1이라는 TNS alias로RAC1에접속할수있
다면모든준비가되었다. RAC1 인스턴스에접속되었는지확인해보도록하
자<리스트1>.
<리스트1> RAC1 인스턴스의 접속 확인
$ sqlplus scott/tiger@rac1
SQL*Plus: Release 9.2.0.3.0 - Production on 화 Jul 8 12:20:46 2003
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
다음에접속됨:
Oracle9i Enterprise Edition Release 9.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production
세션이변경되었습니다.
SQL> select userenv('instance') from dual;
USERENV('INSTANCE')
--------------------------
1
그러면, 이제각각의기능이어떻게작동하는지자세히알아보도록하자.
CTF
CTF(Connection Time Failover)는가장기본적인페일오버설정방법으로,
클라이언트의TNS alias만아래와같이수정해주면된다.
RAC_CTF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
O R A C L E D E V E L O P E R
102 ORACLE KOREA MAGAZINE
(connect_data=
(service_name=RAC)
)
)
로드 밸런싱(load balancing)은 이후에 별도로 자세히 설명하므로, 일
단여기서는로드밸런싱에대한언급은하지않기로하자. 이와같이설정한
다면, 일단RAC_CTF를사용하여접속하는클라이언트들은
1. krrac1의1521 포트로기동된리스너를컨택한다.
2. 그 리스너가RAC라는 서비스를 하고 있다면RAC라는 서비스에 등록되어
있는인스턴스에접속한다.
3. 만일1에서리스너가응답이없거나, 2에서RAC라는서비스가없다면, 다음
에지정된어드레스인krrac2의1521 포트로기동된리스너를컨택한다. 여
기서리스너가응답이없다면에러를리턴하며접속을하지못하게된다.
4. 2와마찬가지과정으로RAC 서비스에등록되어있는인스턴스를접속한다.
여기서RAC 서비스를 찾을 수 없다면, 마찬가지로 에러를 리턴하며 접속을
하지못하게된다.
따라서, 새로이접속하는클라이언트에대하여는krrac1에서어떤장애
가일어나더라도문제없이krrac2로페일오버가된다.
그렇다면, 기존에이미접속되어있던클라이언트들은어떻게될까? 리스
너에만장애가있다면당연히영향이없을것이지만, 만일인스턴스가중단되
었다면? 물론클라이언트는ORA-3113/3114 에러를만나게되며기존의접
속상태가끊어지고, 새로접속하면위와같은과정을거쳐krrac2로접속하
게된다. 실행되고있던DML은살아있는RAC2인스턴스에서트랜잭션복구
를수행하여모두롤백된다.
여기서각호스트의리스너가어떤포트로기동되어있는지, 어떤서비스
에어떤인스턴스가등록되어있는지는<리스트2>와같은방법으로알수있
다.
<리스트2> 각호스트의리스너포트와서비스별인스턴스등록확인
krrac1|/data/oracle> lsnrctl services
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 08-JUL-2003 14:09:47
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac1)(PORT=1521)))
Services Summary...
Service "RAC" has 1 instance(s).
Instance "RAC1", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:1 refused:0 state:ready
LOCAL SERVER
Service "RAC1" has 1 instance(s).
Instance "RAC1", status UNKNOWN, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0
LOCAL SERVER
The command completed successfully
여기서독자들은뭔가좀특이한점을볼수있을것이다. 현재리스너에
는 RAC와 RAC1 두 가지 서비스가 등록되어 있으며, 각각의 서비스에는
RAC1인스턴스가등록되어있다.
그렇다면, 왜 두 가지 서비스가 등록되어 있을까? 이것을 이해하기 위해
서는 Oracle8i Database에서 도입된 동적 등록(dynamic registration) 방
식에대하여우선알아야한다.
위에서status 항목을자세히살펴보면, RAC 서비스에대하여는READY
인반면RAC1 서비스에대하여는UNKNOWN으로나와있는것을볼수있
다. 즉, 리스너는 현재RAC 서비스를 통해서는RAC1 인스턴스가 살아 있다
(READY)는사실을알수있지만, RAC1 서비스를통해서는RAC1 인스턴스
의상태를알수없다(UNKNOWN). 여기서한번RAC1 인스턴스를셧다운
한후똑같은테스트를해보자<리스트3>.
<리스트3> RAC1 인스턴스의셧다운후테스트실행
krrac1|/data/oracle> lsnrctl services listener_rac1
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 08-JUL-2003 14:25:51
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac1)(PORT=1521)))
Services Summary...
Service "RAC1" has 1 instance(s).
Instance "RAC1", status UNKNOWN, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0
LOCAL SERVER
The command completed successfully
그러면, RAC 서비스가사라진것을볼수있다. 반면에, RAC1 서비스는
여전히RAC1인스턴스의상태를모르고있다. 즉, RAC서비스는동적으로등
록된서비스이며, 이러한서비스에등록된인스턴스는지속적으로자신의상
O R A C L E D E V E L O P E R
2003 AUTUMN 103
태를리스너에업데이트시켜준다.
동적등록을구성하는방법은다음과같다.
1. SERVICE_NAMES 파라미터 값을 설정해 준다. 이것이 바로 리스너에 등
록하는서비스의이름으로, 디폴트값은db_name.db_domain이된다. 즉,
예제에서는 db_domain 값이 설정되어 있지 않으므로 그냥 rac가 된다. 주
의할 점은 service_names를 임의로 설정하는 경우 Oracle9i Real
Application Clusters 데이타베이스 내의 페일오버 설정에 참여하는 모든
인스턴스들은같은값으로설정해야한다는것이다. 앞서설명한RAC_CTF
TNS alias를보면service_name 값을RAC로사용하여서로다른리스너
어드레스를등록한것을확인할수있다.
2. LOCAL_LISTENER 파라미터 값을 설정해 준다. 즉 어느 리스너에 자신의
상태를 업데이트시켜 줄 것인지를 정해주는 부분으로, 디폴트 값은
(ADDRESS = (PROTOCOL=TCP)(HOST=)(PORT=1521))이된
다. 즉, 로컬 호스트의 1521 포트로 기동되는 리스너에 대하여는
LOCAL_LISTENER 값을 설정하지 않더라도 자동으로 동적 등록이 설정
된다.
이예제에서는SERVICE_NAMES, LOCAL_LISTENER 값을둘다설정
하지않았지만lsnrctl services에서동적등록이되어있는것을확인할수있
다. 모두 디폴트 값을 취했기 때문이다. 즉, db_name을SERVICE_NAMES
로사용하고, 1521 포트의리스너를사용하고자한다면이예제와같이아무
것도설정할필요가없다.
LOCAL_LISTENER를 설정할 때는 디폴트 값처럼 TNS alias 구문으로
설정해줄수도있지만다른방법도있다. 서버의(클라이언트가아니라서버
임에유의하자) tnsnames.ora 파일에다음과같은항목을추가해보자.
LISTENER_RAC1 =
(description=
(address=(protocol=tcp)(host=krrac1)(port=1521))
)
그리고 init.ora 파일에는 LOCAL_LISTENER=LISTENER_RAC1라고
지정해보자. lsnrctl services에서와마찬가지로동적등록이이루어진것을
확인할수있다. 즉, 클라이언트에서tnsnames.ora 파일에TNS alias를설정
하여사용하듯이, 서버에서도LOCAL_LISTENER에대하여TNS alias를설
정하여사용할수있다. 물론여기서설정하는값은 listener.ora 파일에지정
하는리스너이름과는아무런상관이없다.
Oracle9i Database Release 2(V9.2)부터는LOCAL_LISTENER 값을
인스턴스가기동중인상태에서도아래와같이동적으로바꿀수있다.
SQL>alter system set local_listener='LISTENER_RAC1';
System altered.
이때물론서버의 tnsnames.ora에는LISTENER_RAC1이라는항목이
미리지정되어있어야하며, 만일이것이없을때에는오라클에러가나타나
며실패하게된다. 또한SPFile(Server Parameter File)이아닌텍스트방식
의init.ora를 사용하는 경우 인스턴스를 내렸다 올리면 위 설정은 없어지고
원래대로 돌아가므로, 설정을 지속시키려면 init.ora 파일에 값을 명시적으
로설정해야한다.
자, 그럼여기서한가지의문이생길수있다. ‘그렇다면, 정적으로등록된
서비스(즉위예제에서status UNKNOWN으로등록된RAC1 서비스)는?’
결론적으로 말하면, 동적 등록 방식이 정적 등록 방식을 오버라이드
(override)하게되므로정적등록방식은다음과같이 listener.ora 파일을수
정하여제거하는것이좋다.
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = krrac1)
(PORT = 1521))
)
)
)
여기서또한가지. 바로위에설정한내용이listener.ora의디폴트값이
다. 결국listener.ora 파일에아무런내용이없어도된다는이야기가된다.
사실1521 포트를사용하면서LISTENER라는이름의리스너를사용한
다면실제로listener.ora 파일자체가필요가없다. lsnrctl 명령어는디폴트로
LISTENER라는이름의리스너에대하여수행되므로, 시동/중단하는데에도
아무런지장이없다. 한번listener.ora 파일을제거하고테스트해보도록하
자. 여태까지와마찬가지결과를얻을것이다.
물론, LISTENER라는이름이아닌다른이름의리스너를사용하고자한
다면 1521 포트를 사용하더라도 이름을 지정하기 위해서 listener.ora 파일
이필요하다.
이미눈치빠른독자들은알아챘겠지만, 동적등록방식이우수하므로앞
으로는항상동적등록방식을쓰도록하자는것이다. 동적등록방식은세가
지측면에서과거의정적등록방식보다우수하다.
. 주기적으로 인스턴스가 리스너에 자신의 상태를 알려주므로, CTF 설정에서
인스턴스에장애가있을경우앞서설정한페일오버과정에서장애가발생한
인스턴스에접속을시도하는오버헤드가없다. 즉, 리스너까지만가면인스턴
스의상태를알수있다.
. Oracle9i Database의 새로운 기능인 리스너(커넥션) 로드 밸런싱을 사용
O R A C L E D E V E L O P E R
104 ORACLE KOREA MAGAZINE
할수있다.
. TAF를사용할수있다.
그렇다면TAF란무엇인가? 이것에대해자세히알아보도록하자.
TAF
앞서잠깐설명한대로CTF의약점은기존에접속되어있던클라이언트들에
대해서는다시한번접속을시도해야페일오버가이루어진다는점이다.
바로 이것을 극복할 수 있는 솔루션이 바로 TAF(Transparent
Application Failover)이다. 앞서설정한클라이언트쪽의TNS alias를다음
과같이수정해보자. 물론리스너에는반드시인스턴스가동적으로등록되어
있어야한다.
RAC_TAF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic))
)
)
CTF와 비교하여 다른 점은 failover_mode라는 항목이 설정되었다는
점이다. 이것을설정하는방법을설명하기에앞서, 일단위와같이TAF가설
정되어있는경우에이미접속되어있던클라이언트들은장애상황에서어떻
게되는지부터알아보자. 예를들어, 클라이언트에서100건의레코드를리턴
하는Select를수행중이었고, 현재50건이Fetch된상태에서RAC1 인스턴스
가중단되었다고가정한다면,
1. 살아 있는 인스턴스인 RAC2에서 새로이 Oracle Server Process
(Foreground Process)를띄운다.
2. 이렇게새로이만들어진프로세스로50건을Fetch하던클라이언트의세션
정보가옮겨진다. 이때복구되는내용은다음과같다.
. SQL을실행하던사용자의로그인정보
. 실행하던SQL 명령어
. Fetch하던커서
. 서버측프로그램변수(예를들면, PL/SQL package states)
3. 이렇게 세션 정보가 복구되면 수행되던 Select 문장이 Fetch하던 나머지
50건이Fetch된다. 따라서클라이언트는RAC1 인스턴스에장애가발생했
다는 사실을 전혀 모르게 된다(Transparent Application). 물론 2번 과정
에서세션정보를복구하는과정이있으므로50건Fetch 후다시나머지50
건의Fetch가시작되기까지약간지연될수있다.
TAF와CTF의가장큰차이점은재접속이필요없다는점이다. 앞서CTF
방식에서는 접속되어 있던 클라이언트들은 장애 발생 시 일단 ORA-
3113/3114 에러를만나게되며, 재접속을해야페일오버가되었다는점을기
억하자. 이때기존에접속되어있던클라이언트와별도로새로접속하는클
라이언트들은앞서설명한CTF가작동하여페일오버가이루어진다.
그러면, failover_mode의각각의항목에대하여알아보도록하자.
. TYPE
- SESSION : 이방식은재접속은필요없지만, 예제와는달리Select가Fetch
하던 도중에 장애를 만나면 Fetch가 도중에 실패하게 된다. 데이타 웨어하우
스와같이다량의레코드를한번에Select하는경우가아니라면이방식을쓰
는것이좋다.
- SELECT : 예제와같은방식으로, 재접속도필요없을뿐더러Fetch하던레
코드까지 복구해 준다. 다량의 레코드를 Select하는 애플리케이션에 적절한
방법이다.
- NONE : 디폴트값으로TAF가작동하지않는다.
. METHOD
- BASIC : On-demand 방식으로 페일오버가 필요할 때 살아있는 인스턴스
쪽으로Oracle Server Process를기동시킨다.
- PRECONNECT : 페일오버가 이루어질 인스턴스에 미리 Oracle Server
Process를 기동시켜 페일오버시 발생하는 오버헤드를 미리 줄여 놓는 방식
이다. 물론페일오버속도는향상되지만, 자원을낭비할수있다.
그렇다면, 여기서또의문점이생긴다. PRECONNECT 메소드를사용하
는 경우 미리 어느 인스턴스로 페일오버할지를 결정해 놓아야 한다. 다음과
같이클라이언트의tnsnames.ora를수정해보자.
RAC_TAF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic)(backup=RAC2))
)
)
O R A C L E D E V E L O P E R
2003 AUTUMN 105
RAC2 =
(description=
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC))
)
즉PRECONNECT 메소드를사용하는경우에는반드시backup이라는
항목이함께설정되어야한다. 이때backup에는TNS alias로지정하며, 여기
에 지정할 TNS alias는 반드시 미리 설정되어 있어야 한다(예제에서는
RAC2). 특히, 이때지정한TNS alias가올바로설정된값이아니어도접속할
때따로에러를리턴하지않는다는점에주의하자.
물론, 이예제에서는2노드환경이므로한쪽에서장애가발생하면나머
지살아있는쪽은하나밖에없으므로왜이것이필요할까궁금해하는독자
들이있을것이다. 위와같이설정해놓고RAC_TAF라는TNS alias로접속한
후 <리스트 4>와 같이 SQL을 실행해 보자. 참고로 <리스트 4>의 SQL은
PRECONNECT 메소드뿐만아니라모든경우의TAF 설정이제대로작동하
는지알아보기위해서사용할수있다.
<리스트4> TAF 설정이올바로되었는지확인하는SQL
SQL> SELECT
2 INST_ID, SID, MACHINE, FAILOVER_TYPE, FAILOVER_METHOD, FAILED_OVER
3 FROM GV$SESSION
4 WHERE USERNAME='SYSTEM'
5 AND PROGRAM NOT LIKE '%(P%';
INST_ID SID MACHINE FAILOVER FAILOVER_METHOD FAILED
--------------------------------------------------------------------------------------
1 20 ORACLE\leesb-kr SELECT PRECONNECT NO
2 19 ORACLE\leesb-kr NONE NONE NO
이렇게PRECONNECT 메소드를 사용하는 경우에는 최초에 접속하는
주(primary) 인스턴스와백업인스턴스에동시에접속한다는것을알수있
다. 이때RAC1인스턴스를셧다운시키면다음과같은결과가나와야한다.
INST_ID SID MACHINE FAILOVER FAILOVER_METHOD FAILED
--------------------------------------------------------------------------------------
2 19 ORACLE\leesb-kr SELECT PRECONNECT YES
여기서주목해야할점은PRECONNECT 메소드를사용할때는항상주
인스턴스와백업인스턴스를지정해야하므로로드밸런싱을할수없다는사
실이다. 따라서PRECONNECT 메소드는각인스턴스에접속하는클라이언
트가업무별/지역별로분할되어있는경우에사용할수있다.
페일오버 테스트 시나리오
자, 이렇게페일오버를설정했다면실제로장애상황별로제대로작동하는지
살펴보아야할것이다. 보통페일오버테스트에서고려하는장애상황은다음
과같다.
. 오라클 인스턴스 장애 : 간단하게shutdown abort 명령으로 인스턴스 장
애상황을만들수있다.
. 노드 장애(네트워크 장애) : 클라이언트 입장에서는 노드 자체가 장애가 있
는 경우(reboot 또는 halt 명령)나 네트워크 장애가 있는 경우(네트워크 디바
이스의 셧다운 또는 네트워크 라인의 unplug)나 같은 상황이므로 똑 같은 결
과가나와야한다.
. 리스너장애: 간단하게리스너프로세스를중단하든지lsnrctl stop으로셧
다운해서 장애 상황을 만들 수 있다. 인스턴스는 살아 있으면서 리스너만 장
애가있는경우에는항상기존에접속되어있던클라이언트는페일오버설정
과 관계 없이 아무런 문제가 없어야 하며, 오직 새로이 접속하는 클라이언트
만페일오버가이루어진다는점을기억하자.
이세가지장애상황에서페일오버가모두정상적으로이루어진다면설
정이성공적으로이루어졌다고볼수있다.
마지막으로 클라이언트 페일오버를 테스트할 때, 오라클 인터커넥트
(Oracle9i Real Application Clusters 노드간의개별네트워크)에대한장애
는클라이언트페일오버와전혀상관이없으며, 이인터커넥트의장애발생시
에는인스턴스의장애가당연히뒤따르므로이를고려하여테스트하여야한
다. 오라클인터커넥트의장애발생시어떤결과가일어나는가에대해서는본
지2003년봄호에실린필자의‘Oracle9i Real Application Clusters - Cache
Fusion의작동원리와활용’을참고하기바란다.
클라이언트로드밸런싱vs 리스너로드밸런싱
자, 이제는Oracle9i Real Application Clusters의로드밸런싱에대해알아
보도록 하자. ‘로드 밸런싱(load balancing)’이란 말 그대로 공평하게 부하
(load)를 나누어 준다는 뜻이다. 즉, 100개의 클라이언트가 있다면 2노드
Oracle9i Real Application Clusters 환경에서는 각 인스턴스별로 50개씩
똑같이 나누어 주고 싶을 것이고, 차후에 다시50개의 새로운 클라이언트가
접속한다면다시각각25개씩나누어주어언제나공평하게부하를유지하고
싶을것이다.
하지만, 이제까지의예제와같이TNS alias에서load_balance=off로설
정한경우에는어느클라이언트가어느인스턴스로접속할지수동으로모두
설정해 주어야 하는 번거로움이 있었다. 만일 이것이 자동으로 된다면? 즉,
O R A C L E D E V E L O P E R
106 ORACLE KOREA MAGAZINE
100개의 클라이언트가 무작위로 접속할 때 자동으로50개씩 나누어진다면
훨씬더편리할것이다.
사실 Oracle9i Real Application Clusters가 나오기 이전에 Oracle
Parallel Server를 사용하는 고객들은 로드 밸런싱을 잘 사용하지 못했다고
할수있다. 왜냐하면, Oracle Parallel Server에서발생하는핑(ping) 현상으
로인해보통불가피하게노드별로데이타를분할하여데이타베이스를구성
하므로, 업무별/지역별로클라이언트를나누어특정인스턴스를지정해서접
속해야했기때문이다.
하지만, Oracle9i Real Application Clusters에서완벽하게이루어지는
Cache Fusion의 기능으로더 이상 데이타의분할이 필요 없게 되었으므로,
클라이언트는Oracle9i Real Application Clusters로구성된데이타베이스
내의어떤인스턴스에접속하더라도성능에는아무런영향을주지않는다.
오라클의로드밸런싱설정은다음두가지가있다.
. 클라이언트로드밸런싱: 클라이언트가같은SERVICE_NAME을사용하
는인스턴스들중에무작위로선택하여접속하는방법이다.
. 리스너(커넥션) 로드 밸런싱 : Oracle9i Real Application Clusters의새
로운기능으로리스너가각인스턴스의부하에대한정보를가지고있어서항
상부하가덜걸린인스턴스쪽으로클라이언트를접속시켜주는방법이다.
그러면이제각각의방법을어떻게구현할수있는지차례로살펴보자.
클라이언트 로드 밸런싱
앞서설정했던BASIC메소드의TAF 설정을다음과같이수정해보자.
RAC_TAF =
(description=
(load_balance=on)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic))
)
)
다른것은그대로둔채로load_balance 부분만on으로설정하면클라
이언트로드밸런싱이구성된다. 이제반복적으로접속하여결과를보도록하
자.
SQL> conn scott/tiger@rac_taf
Connected.
SQL> select userenv('instance') from dual;
USERENV('INSTANCE')
--------------------------
2
SQL> conn scott/tiger@rac_taf
Connected.
SQL> select userenv('instance') from dual;
USERENV('INSTANCE')
--------------------------
1
위와같이클라이언트는인스턴스를바꿔가며RAC1, RAC2에무작위로
접속하는 것을 볼 수 있다. 라운드로빈(round-robin) 방식이 아닌 무작위
(random) 방식이므로, 특별한패턴을찾을수는없지만, 접속횟수가많아질
수록 균일하게 분배되는 것을 알 수 있을 것이다. 즉, 예제와 같이 2노드의
Oracle9i Real Application Clusters 환경에서100회반복하여접속한다면,
거의50:50으로나누어지는것을확인할수있을것이다.
클라이언트로드밸런싱을하는경우특별히동적등록이필요하지는않
으나, 예제와같이TAF와함께사용하는경우에는반드시동적등록이구성
되어있어야한다.
리스너(커넥션) 로드 밸런싱
최초에RAC1 인스턴스에는100개의클라이언트, RAC2 인스턴스에는10개
의클라이언트가접속되어있었다고가정하자. 이후에다시100개의새로운
클라이언트를클라이언트로드밸런싱을설정하여접속시킨다면? 결과는새
로운100개의클라이언트들은50:50으로균일하게분배되어결국최종적으
로는RAC1인스턴스는150개, RAC2 인스턴스에는60개의클라이언트가붙
을것이다.
이렇게되면RAC1인스턴스입장에서는불공평한결과가될수있다. 즉
RAC2인스턴스가훨씬더여유가있다는것을미리알아서, 새로이들어오는
100개의클라이언트를5:95로분배하여결국105:105가되도록해준다면각
각의인스턴스입장에서는언제나공평한결과를만들수있다.
바로이것이Oracle9i Real Application Clusters에서새로등장한리스
너(커넥션) 로드 밸런싱이며, 이것을 위해서는 서버쪽의 tnsnames.ora와
init.ora에다음과같은설정을추가해야한다. krrac1의tnsnames.ora에다
음과같은항목을추가해보자.
LISTENER_RAC2 =
(description=
(address=(protocol=tcp)(host=krrac2)(port=1521))
)
그리고SYSDBA사용자로다음과같이remote_listener 파라미터값을
변경해보자.
SQL> alter system set remote_listener='LISTENER_RAC2';
System altered.
이제krrac2(krrac1이아님)의리스너를확인해보자. <리스트5>와같이
RAC 서비스에기존에등록되어있던RAC2 인스턴스와함께, RAC1 인스턴
스도추가로동적으로등록되어있는것을볼수있다.
<리스트5> 리스너로드밸런싱에서리스너확인
krrac2|/data/oracle> lsnrctl services
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 14-JUL-2003 15:29:55
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac2)(PORT=1521)))
Services Summary...
Service "RAC" has 2 instance(s).
Instance "RAC1", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0 state:ready
REMOTE SERVER
(DESCRIPTION=(address=(protocol=tcp)(host=krrac1)(port=1521)))
Instance "RAC2", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:25 refused:0 state:ready
LOCAL SERVER
The command completed successfully
그러면, 이제 krrac2의 tnsnames.ora, RAC2 인스턴스의
remote_listener 값을마찬가지로올바르게설정했다면krrac1의리스너에
도<리스트 6>과같이RAC1, RAC2 인스턴스가모두등록되어있는것을확
인할수있을것이다.
<리스트6> 리스너로드밸런싱에서인스턴스의등록확인
krrac1|/data/oracle> lsnrctl services
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 14-JUL-2003 15:33:52
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac2)(PORT=1521)))
Services Summary...
Service "RAC" has 2 instance(s).
Instance "RAC1", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0 state:ready
REMOTE SERVER
(DESCRIPTION=(address=(protocol=tcp)(host=krrac1)(port=1521)))
Instance "RAC2", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:25 refused:0 state:ready
LOCAL SERVER
The command completed successfully
앞서설명한동적등록이무엇을의미하는가를기억한다면, 여기서각각
의인스턴스가remote_listener 파라미터를사용함으로써상대방노드의리
스너에자신의상태를지속적으로업데이트해주고있다는것을눈치챌수있
다.
즉, 예제와같이리스너(커넥션) 로드밸런싱을사용하는경우클라이언
트는접속할때다음과같은과정을거치게된다.
1. 클라이언트는 일단 TNS alias의 address_list의 첫 번째 항목인 krrac1의
1521 포트로기동된리스너에컨택한다.
2. krrac1의 리스너는RAC1, RAC2 인스턴스가 모두 등록되어 있으며, 각인
스턴스는 자신이 서비스가 가능한 상태인지의 여부와, 자신이 가지고 있는
부하(접속해 있는 클라이언트의 개수)를 지속적으로 업데이트해 주고 있으
므로, 1에서리스너에컨택한클라이언트는RAC1과RAC2 중어느것이적
은수의클라이언트를가지고있는지알수있다.
3. 만일 RAC1의 클라이언트 수가 적다면, 로컬 노드(krrac1)에서 Oracle
Server Process(Foreground Process)를만들어서커넥션을맺어준다.
4. 만일RAC2의클라이언트수가적다면, address_list의다음에나오는항목
(리모트 노드 : krrac2의 1521 포트)에 등록되어 있는 리스너로 리다이렉트
시켜준다.
5. krrac2의리스너는이제Oracle Server Process(Foreground Process)
를만들어서 커넥션을맺어준다.
따라서, 리스너의서비스에remote_listener를사용하여Oracle9i Real
Application Clusters의 모든 인스턴스가 등록되어 있기만 하다면, 언제나
공평한분배(로드밸런싱)가이루어질수있다.
설정후테스트는다음과같이해볼수있다.
1. RAC1 인스턴스에만로드밸런싱을사용하지않고미리상당수의커넥션을
맺어놓는다(이를테면10개라고하자.)
2. 이제 RAC_TAF TNS alias를 가지고 반복적으로 접속해 보자. 10개까지
는 RAC2에만 접속되어 각 인스턴스에 10개씩의 클라이언트가 만들어질
것이다.
3. 이어서 지속적으로 RAC_TAF TNS alias를 가지고 반복적으로 접속해 본
다면, 이제는 각 인스턴스에 거의 번갈아서 접속하면서 클라이언트 개수의
총합이언제나50:50으로유지되는것을볼수있을것이다.
마지막으로 주의할 점은, 리스너(커넥션) 로드 밸런싱은 항상 클라이언
트로드밸런싱을오버라이드하므로, remote_listener가설정되어리스너에
여러 인스턴스가 등록되어 있는 경우, 아래와 같이 TNS alias에서 클라이언
트로드밸런싱을사용하지않더라도, 리스너(커넥션) 로드밸런싱은계속이
루어진다는사실이다. 즉, 아래와같이TNS alias를설정한경우에로드밸런
싱이 일어나고 있다면, 일단 remote_listener가 설정되어 있는지 우선 확인
해보도록하자.
RAC_TAF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic))
)
remote_listener 값은Oracle9i Database Release 2(9.2)부터는아래
와같이동적으로해제할수있다.
SQL> alter system set remote_listener='';
System altered.
이제까지로드밸런싱을설명하면서계속TAF를예로들었지만, CTF 설
정(failover_mode 부분제고)으로도똑같은로드밸런싱을구현할수있으
며, 예제와똑같은테스트를할수있다.
난공불락의Oracle9i Real Application Clusters
필자가Oracle9i Real Application Clusters를도입하고자하는독자들에게
하고싶은말은, 일단싱글인스턴스환경에서시스템을문제없이사용해왔다
면, Oracle9i Real Application Clusters로의전환이후에도문제없는시스
템을 유지할 수 있으며, 나아가 오라클이 자랑하는 ‘난공불락 Oracle9i Real
Application Clusters’의놀라운기능을마음껏누릴수있다는것이다.
마지막으로필자가3회의연재를통해언급한몇가지주의사항을다시
한번정리하며끝을맺기로한다.
. 싱글 인스턴스로 운영중이던 애플리케이션은 Oracle9i Real Application
Clusters로 전환 시 Cache Fusion이 완벽하게 작동하므로 별도의 데이타
분할이필요없다.
. Oracle9i Real Application Clusters에서 고속 인터커넥트는 Cache
Fusion을위해필수이며, HA로구성되어있는것이바람직하다.
. 싱글 인스턴스 환경에서 튜닝 되지 않은 SQL들은 Oracle9i Real
Application Clusters 환경에서 더욱 성능이 악화될 수 있으니, Oracle9i
Real Application Clusters 전환 전에 애플리케이션을 반드시 점검하도록
하자.
. global cache cr request가과다하게보이는경우, 무엇보다도SQL 튜닝이
되어있는지먼저확인하고, 읽기액세스가대부분인테이블스페이스에한하
여gc_files_to_locks 파라미터를신중하게고려해본다.
. 페일오버설정은각장애유형별로철저히테스트해보아야하며, 애플리케이
션분할이되어있지않다면로드밸런싱을하는것이바람직하다.
아마도 독자들이 Oracle9i Real Application Clusters를 도입하는 가장 큰
이유는 Oracle9i Real Application Clusters가 고가용성(HA)을 보장해 주
기때문일것인데, 실제로HA를구현하기위해서가장중요한부분이애플리
케이션 페일오버(application failover)이다. 애플리케이션 페일오버를 간
단히설명하면, Oracle9i Real Application Clusters 환경에서하나의노드
에장애가발생했을때애플리케이션은나머지살아있는노드들중의하나로
부터서비스를받게되므로, 엔드유저들은장애가발생했는지조차모르는것
이다. 이것이바로오라클에서Oracle9i Real Application Clusters를‘난공
불락(Unbreakable)’이라고내세우는이유이다.
최근에는HA에 대한 관심이 높아지면서 플랫폼 벤더에서도 여러 가지
HA 솔루션 - 이를테면, IP 스위치오버 - 을 제공한다. Oracle9i Real
Application Clusters 사용 고객이 이러한 플랫폼 솔루션을 훌륭하게 함께
사용하는경우도많이있지만, 이번호에서는혼돈을피하기위해100% 오라
클이제공하는솔루션만을다루도록한다.
Oracle9i Real Application Clusters에서제공하는페일오버기능에는
CTF(Connection Time Failover)와 TAF(Transparent Application
Failover)가있다. 이두가지기능모두는Oracle8i Parallel Server에서부터
제공되던 기능이다. 그런데, 많은 고객들이CTF와TAF가 상호 배타적인 기
능이라고여기는것같은데, TAF는CTF 기능위의부가적인기능이다. 따라
서, CTF를사용할것인지TAF를사용할것인지고민할필요없이TAF를사용
할것인지아닌지의여부만선택하면된다.
이글의기반이되는필자의테스트환경은다음과같다. 앞으로이어지
는테스트에서는항상이전의설정을기본으로변경사항만추가하도록하
겠다.
. 데이타베이스서버 >>> 2노드의Oracle9i Real Application Clusters
. 운영체제: Sun Solaris 8
. 오라클데이타베이스버전: Oracle9i Database Release 2(9.2.0.3) 64비트
. 호스트명(공용네트워크) : krrac1, krrac2
. ORACLE_SID : RAC1(krrac1), RAC2(krrac2)
. init.ora 파라미터
local_listener=(지정 안함)
remote_listener=(지정 안함)
service_names=(지정 안함)
db_name='rac'
rac1.instance_name='rac1'
rac2.instance_name='rac2'
. listener.ora(krrac1. krrac2는 HOST와 SID_NAME만 각각 krrac2,
RAC2이며나머지는동일)
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = krrac1)
(PORT = 1521))
)
)
)
SID_LIST_LISTENER =
(SID_LIST =
(SID_DESC =
(ORACLE_HOME = /data/oracle)
(SID_NAME = RAC1)
)
)
. Oracle*Net 클라이언트(SQL*Plus)
. 운영체제 : Windows 2000 Professional
. 오라클클라이언트버전 : Oracle9i Database Release 2(9.2.0.3)
. tnsnames.ora
RAC1 =
(description=
(address=(protocol=tcp)(host=krrac1)(port=1521))
(connect_data=
(service_name=RAC))
)
자, 이제클라이언트에서rac1이라는 TNS alias로RAC1에접속할수있
다면모든준비가되었다. RAC1 인스턴스에접속되었는지확인해보도록하
자<리스트1>.
<리스트1> RAC1 인스턴스의 접속 확인
$ sqlplus scott/tiger@rac1
SQL*Plus: Release 9.2.0.3.0 - Production on 화 Jul 8 12:20:46 2003
Copyright (c) 1982, 2002, Oracle Corporation. All rights reserved.
다음에접속됨:
Oracle9i Enterprise Edition Release 9.2.0.3.0 - 64bit Production
With the Partitioning, Real Application Clusters, OLAP and Oracle Data Mining options
JServer Release 9.2.0.3.0 - Production
세션이변경되었습니다.
SQL> select userenv('instance') from dual;
USERENV('INSTANCE')
--------------------------
1
그러면, 이제각각의기능이어떻게작동하는지자세히알아보도록하자.
CTF
CTF(Connection Time Failover)는가장기본적인페일오버설정방법으로,
클라이언트의TNS alias만아래와같이수정해주면된다.
RAC_CTF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
O R A C L E D E V E L O P E R
102 ORACLE KOREA MAGAZINE
(connect_data=
(service_name=RAC)
)
)
로드 밸런싱(load balancing)은 이후에 별도로 자세히 설명하므로, 일
단여기서는로드밸런싱에대한언급은하지않기로하자. 이와같이설정한
다면, 일단RAC_CTF를사용하여접속하는클라이언트들은
1. krrac1의1521 포트로기동된리스너를컨택한다.
2. 그 리스너가RAC라는 서비스를 하고 있다면RAC라는 서비스에 등록되어
있는인스턴스에접속한다.
3. 만일1에서리스너가응답이없거나, 2에서RAC라는서비스가없다면, 다음
에지정된어드레스인krrac2의1521 포트로기동된리스너를컨택한다. 여
기서리스너가응답이없다면에러를리턴하며접속을하지못하게된다.
4. 2와마찬가지과정으로RAC 서비스에등록되어있는인스턴스를접속한다.
여기서RAC 서비스를 찾을 수 없다면, 마찬가지로 에러를 리턴하며 접속을
하지못하게된다.
따라서, 새로이접속하는클라이언트에대하여는krrac1에서어떤장애
가일어나더라도문제없이krrac2로페일오버가된다.
그렇다면, 기존에이미접속되어있던클라이언트들은어떻게될까? 리스
너에만장애가있다면당연히영향이없을것이지만, 만일인스턴스가중단되
었다면? 물론클라이언트는ORA-3113/3114 에러를만나게되며기존의접
속상태가끊어지고, 새로접속하면위와같은과정을거쳐krrac2로접속하
게된다. 실행되고있던DML은살아있는RAC2인스턴스에서트랜잭션복구
를수행하여모두롤백된다.
여기서각호스트의리스너가어떤포트로기동되어있는지, 어떤서비스
에어떤인스턴스가등록되어있는지는<리스트2>와같은방법으로알수있
다.
<리스트2> 각호스트의리스너포트와서비스별인스턴스등록확인
krrac1|/data/oracle> lsnrctl services
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 08-JUL-2003 14:09:47
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac1)(PORT=1521)))
Services Summary...
Service "RAC" has 1 instance(s).
Instance "RAC1", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:1 refused:0 state:ready
LOCAL SERVER
Service "RAC1" has 1 instance(s).
Instance "RAC1", status UNKNOWN, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0
LOCAL SERVER
The command completed successfully
여기서독자들은뭔가좀특이한점을볼수있을것이다. 현재리스너에
는 RAC와 RAC1 두 가지 서비스가 등록되어 있으며, 각각의 서비스에는
RAC1인스턴스가등록되어있다.
그렇다면, 왜 두 가지 서비스가 등록되어 있을까? 이것을 이해하기 위해
서는 Oracle8i Database에서 도입된 동적 등록(dynamic registration) 방
식에대하여우선알아야한다.
위에서status 항목을자세히살펴보면, RAC 서비스에대하여는READY
인반면RAC1 서비스에대하여는UNKNOWN으로나와있는것을볼수있
다. 즉, 리스너는 현재RAC 서비스를 통해서는RAC1 인스턴스가 살아 있다
(READY)는사실을알수있지만, RAC1 서비스를통해서는RAC1 인스턴스
의상태를알수없다(UNKNOWN). 여기서한번RAC1 인스턴스를셧다운
한후똑같은테스트를해보자<리스트3>.
<리스트3> RAC1 인스턴스의셧다운후테스트실행
krrac1|/data/oracle> lsnrctl services listener_rac1
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 08-JUL-2003 14:25:51
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac1)(PORT=1521)))
Services Summary...
Service "RAC1" has 1 instance(s).
Instance "RAC1", status UNKNOWN, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0
LOCAL SERVER
The command completed successfully
그러면, RAC 서비스가사라진것을볼수있다. 반면에, RAC1 서비스는
여전히RAC1인스턴스의상태를모르고있다. 즉, RAC서비스는동적으로등
록된서비스이며, 이러한서비스에등록된인스턴스는지속적으로자신의상
O R A C L E D E V E L O P E R
2003 AUTUMN 103
태를리스너에업데이트시켜준다.
동적등록을구성하는방법은다음과같다.
1. SERVICE_NAMES 파라미터 값을 설정해 준다. 이것이 바로 리스너에 등
록하는서비스의이름으로, 디폴트값은db_name.db_domain이된다. 즉,
예제에서는 db_domain 값이 설정되어 있지 않으므로 그냥 rac가 된다. 주
의할 점은 service_names를 임의로 설정하는 경우 Oracle9i Real
Application Clusters 데이타베이스 내의 페일오버 설정에 참여하는 모든
인스턴스들은같은값으로설정해야한다는것이다. 앞서설명한RAC_CTF
TNS alias를보면service_name 값을RAC로사용하여서로다른리스너
어드레스를등록한것을확인할수있다.
2. LOCAL_LISTENER 파라미터 값을 설정해 준다. 즉 어느 리스너에 자신의
상태를 업데이트시켜 줄 것인지를 정해주는 부분으로, 디폴트 값은
(ADDRESS = (PROTOCOL=TCP)(HOST=)(PORT=1521))이된
다. 즉, 로컬 호스트의 1521 포트로 기동되는 리스너에 대하여는
LOCAL_LISTENER 값을 설정하지 않더라도 자동으로 동적 등록이 설정
된다.
이예제에서는SERVICE_NAMES, LOCAL_LISTENER 값을둘다설정
하지않았지만lsnrctl services에서동적등록이되어있는것을확인할수있
다. 모두 디폴트 값을 취했기 때문이다. 즉, db_name을SERVICE_NAMES
로사용하고, 1521 포트의리스너를사용하고자한다면이예제와같이아무
것도설정할필요가없다.
LOCAL_LISTENER를 설정할 때는 디폴트 값처럼 TNS alias 구문으로
설정해줄수도있지만다른방법도있다. 서버의(클라이언트가아니라서버
임에유의하자) tnsnames.ora 파일에다음과같은항목을추가해보자.
LISTENER_RAC1 =
(description=
(address=(protocol=tcp)(host=krrac1)(port=1521))
)
그리고 init.ora 파일에는 LOCAL_LISTENER=LISTENER_RAC1라고
지정해보자. lsnrctl services에서와마찬가지로동적등록이이루어진것을
확인할수있다. 즉, 클라이언트에서tnsnames.ora 파일에TNS alias를설정
하여사용하듯이, 서버에서도LOCAL_LISTENER에대하여TNS alias를설
정하여사용할수있다. 물론여기서설정하는값은 listener.ora 파일에지정
하는리스너이름과는아무런상관이없다.
Oracle9i Database Release 2(V9.2)부터는LOCAL_LISTENER 값을
인스턴스가기동중인상태에서도아래와같이동적으로바꿀수있다.
SQL>alter system set local_listener='LISTENER_RAC1';
System altered.
이때물론서버의 tnsnames.ora에는LISTENER_RAC1이라는항목이
미리지정되어있어야하며, 만일이것이없을때에는오라클에러가나타나
며실패하게된다. 또한SPFile(Server Parameter File)이아닌텍스트방식
의init.ora를 사용하는 경우 인스턴스를 내렸다 올리면 위 설정은 없어지고
원래대로 돌아가므로, 설정을 지속시키려면 init.ora 파일에 값을 명시적으
로설정해야한다.
자, 그럼여기서한가지의문이생길수있다. ‘그렇다면, 정적으로등록된
서비스(즉위예제에서status UNKNOWN으로등록된RAC1 서비스)는?’
결론적으로 말하면, 동적 등록 방식이 정적 등록 방식을 오버라이드
(override)하게되므로정적등록방식은다음과같이 listener.ora 파일을수
정하여제거하는것이좋다.
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = krrac1)
(PORT = 1521))
)
)
)
여기서또한가지. 바로위에설정한내용이listener.ora의디폴트값이
다. 결국listener.ora 파일에아무런내용이없어도된다는이야기가된다.
사실1521 포트를사용하면서LISTENER라는이름의리스너를사용한
다면실제로listener.ora 파일자체가필요가없다. lsnrctl 명령어는디폴트로
LISTENER라는이름의리스너에대하여수행되므로, 시동/중단하는데에도
아무런지장이없다. 한번listener.ora 파일을제거하고테스트해보도록하
자. 여태까지와마찬가지결과를얻을것이다.
물론, LISTENER라는이름이아닌다른이름의리스너를사용하고자한
다면 1521 포트를 사용하더라도 이름을 지정하기 위해서 listener.ora 파일
이필요하다.
이미눈치빠른독자들은알아챘겠지만, 동적등록방식이우수하므로앞
으로는항상동적등록방식을쓰도록하자는것이다. 동적등록방식은세가
지측면에서과거의정적등록방식보다우수하다.
. 주기적으로 인스턴스가 리스너에 자신의 상태를 알려주므로, CTF 설정에서
인스턴스에장애가있을경우앞서설정한페일오버과정에서장애가발생한
인스턴스에접속을시도하는오버헤드가없다. 즉, 리스너까지만가면인스턴
스의상태를알수있다.
. Oracle9i Database의 새로운 기능인 리스너(커넥션) 로드 밸런싱을 사용
O R A C L E D E V E L O P E R
104 ORACLE KOREA MAGAZINE
할수있다.
. TAF를사용할수있다.
그렇다면TAF란무엇인가? 이것에대해자세히알아보도록하자.
TAF
앞서잠깐설명한대로CTF의약점은기존에접속되어있던클라이언트들에
대해서는다시한번접속을시도해야페일오버가이루어진다는점이다.
바로 이것을 극복할 수 있는 솔루션이 바로 TAF(Transparent
Application Failover)이다. 앞서설정한클라이언트쪽의TNS alias를다음
과같이수정해보자. 물론리스너에는반드시인스턴스가동적으로등록되어
있어야한다.
RAC_TAF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic))
)
)
CTF와 비교하여 다른 점은 failover_mode라는 항목이 설정되었다는
점이다. 이것을설정하는방법을설명하기에앞서, 일단위와같이TAF가설
정되어있는경우에이미접속되어있던클라이언트들은장애상황에서어떻
게되는지부터알아보자. 예를들어, 클라이언트에서100건의레코드를리턴
하는Select를수행중이었고, 현재50건이Fetch된상태에서RAC1 인스턴스
가중단되었다고가정한다면,
1. 살아 있는 인스턴스인 RAC2에서 새로이 Oracle Server Process
(Foreground Process)를띄운다.
2. 이렇게새로이만들어진프로세스로50건을Fetch하던클라이언트의세션
정보가옮겨진다. 이때복구되는내용은다음과같다.
. SQL을실행하던사용자의로그인정보
. 실행하던SQL 명령어
. Fetch하던커서
. 서버측프로그램변수(예를들면, PL/SQL package states)
3. 이렇게 세션 정보가 복구되면 수행되던 Select 문장이 Fetch하던 나머지
50건이Fetch된다. 따라서클라이언트는RAC1 인스턴스에장애가발생했
다는 사실을 전혀 모르게 된다(Transparent Application). 물론 2번 과정
에서세션정보를복구하는과정이있으므로50건Fetch 후다시나머지50
건의Fetch가시작되기까지약간지연될수있다.
TAF와CTF의가장큰차이점은재접속이필요없다는점이다. 앞서CTF
방식에서는 접속되어 있던 클라이언트들은 장애 발생 시 일단 ORA-
3113/3114 에러를만나게되며, 재접속을해야페일오버가되었다는점을기
억하자. 이때기존에접속되어있던클라이언트와별도로새로접속하는클
라이언트들은앞서설명한CTF가작동하여페일오버가이루어진다.
그러면, failover_mode의각각의항목에대하여알아보도록하자.
. TYPE
- SESSION : 이방식은재접속은필요없지만, 예제와는달리Select가Fetch
하던 도중에 장애를 만나면 Fetch가 도중에 실패하게 된다. 데이타 웨어하우
스와같이다량의레코드를한번에Select하는경우가아니라면이방식을쓰
는것이좋다.
- SELECT : 예제와같은방식으로, 재접속도필요없을뿐더러Fetch하던레
코드까지 복구해 준다. 다량의 레코드를 Select하는 애플리케이션에 적절한
방법이다.
- NONE : 디폴트값으로TAF가작동하지않는다.
. METHOD
- BASIC : On-demand 방식으로 페일오버가 필요할 때 살아있는 인스턴스
쪽으로Oracle Server Process를기동시킨다.
- PRECONNECT : 페일오버가 이루어질 인스턴스에 미리 Oracle Server
Process를 기동시켜 페일오버시 발생하는 오버헤드를 미리 줄여 놓는 방식
이다. 물론페일오버속도는향상되지만, 자원을낭비할수있다.
그렇다면, 여기서또의문점이생긴다. PRECONNECT 메소드를사용하
는 경우 미리 어느 인스턴스로 페일오버할지를 결정해 놓아야 한다. 다음과
같이클라이언트의tnsnames.ora를수정해보자.
RAC_TAF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic)(backup=RAC2))
)
)
O R A C L E D E V E L O P E R
2003 AUTUMN 105
RAC2 =
(description=
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC))
)
즉PRECONNECT 메소드를사용하는경우에는반드시backup이라는
항목이함께설정되어야한다. 이때backup에는TNS alias로지정하며, 여기
에 지정할 TNS alias는 반드시 미리 설정되어 있어야 한다(예제에서는
RAC2). 특히, 이때지정한TNS alias가올바로설정된값이아니어도접속할
때따로에러를리턴하지않는다는점에주의하자.
물론, 이예제에서는2노드환경이므로한쪽에서장애가발생하면나머
지살아있는쪽은하나밖에없으므로왜이것이필요할까궁금해하는독자
들이있을것이다. 위와같이설정해놓고RAC_TAF라는TNS alias로접속한
후 <리스트 4>와 같이 SQL을 실행해 보자. 참고로 <리스트 4>의 SQL은
PRECONNECT 메소드뿐만아니라모든경우의TAF 설정이제대로작동하
는지알아보기위해서사용할수있다.
<리스트4> TAF 설정이올바로되었는지확인하는SQL
SQL> SELECT
2 INST_ID, SID, MACHINE, FAILOVER_TYPE, FAILOVER_METHOD, FAILED_OVER
3 FROM GV$SESSION
4 WHERE USERNAME='SYSTEM'
5 AND PROGRAM NOT LIKE '%(P%';
INST_ID SID MACHINE FAILOVER FAILOVER_METHOD FAILED
--------------------------------------------------------------------------------------
1 20 ORACLE\leesb-kr SELECT PRECONNECT NO
2 19 ORACLE\leesb-kr NONE NONE NO
이렇게PRECONNECT 메소드를 사용하는 경우에는 최초에 접속하는
주(primary) 인스턴스와백업인스턴스에동시에접속한다는것을알수있
다. 이때RAC1인스턴스를셧다운시키면다음과같은결과가나와야한다.
INST_ID SID MACHINE FAILOVER FAILOVER_METHOD FAILED
--------------------------------------------------------------------------------------
2 19 ORACLE\leesb-kr SELECT PRECONNECT YES
여기서주목해야할점은PRECONNECT 메소드를사용할때는항상주
인스턴스와백업인스턴스를지정해야하므로로드밸런싱을할수없다는사
실이다. 따라서PRECONNECT 메소드는각인스턴스에접속하는클라이언
트가업무별/지역별로분할되어있는경우에사용할수있다.
페일오버 테스트 시나리오
자, 이렇게페일오버를설정했다면실제로장애상황별로제대로작동하는지
살펴보아야할것이다. 보통페일오버테스트에서고려하는장애상황은다음
과같다.
. 오라클 인스턴스 장애 : 간단하게shutdown abort 명령으로 인스턴스 장
애상황을만들수있다.
. 노드 장애(네트워크 장애) : 클라이언트 입장에서는 노드 자체가 장애가 있
는 경우(reboot 또는 halt 명령)나 네트워크 장애가 있는 경우(네트워크 디바
이스의 셧다운 또는 네트워크 라인의 unplug)나 같은 상황이므로 똑 같은 결
과가나와야한다.
. 리스너장애: 간단하게리스너프로세스를중단하든지lsnrctl stop으로셧
다운해서 장애 상황을 만들 수 있다. 인스턴스는 살아 있으면서 리스너만 장
애가있는경우에는항상기존에접속되어있던클라이언트는페일오버설정
과 관계 없이 아무런 문제가 없어야 하며, 오직 새로이 접속하는 클라이언트
만페일오버가이루어진다는점을기억하자.
이세가지장애상황에서페일오버가모두정상적으로이루어진다면설
정이성공적으로이루어졌다고볼수있다.
마지막으로 클라이언트 페일오버를 테스트할 때, 오라클 인터커넥트
(Oracle9i Real Application Clusters 노드간의개별네트워크)에대한장애
는클라이언트페일오버와전혀상관이없으며, 이인터커넥트의장애발생시
에는인스턴스의장애가당연히뒤따르므로이를고려하여테스트하여야한
다. 오라클인터커넥트의장애발생시어떤결과가일어나는가에대해서는본
지2003년봄호에실린필자의‘Oracle9i Real Application Clusters - Cache
Fusion의작동원리와활용’을참고하기바란다.
클라이언트로드밸런싱vs 리스너로드밸런싱
자, 이제는Oracle9i Real Application Clusters의로드밸런싱에대해알아
보도록 하자. ‘로드 밸런싱(load balancing)’이란 말 그대로 공평하게 부하
(load)를 나누어 준다는 뜻이다. 즉, 100개의 클라이언트가 있다면 2노드
Oracle9i Real Application Clusters 환경에서는 각 인스턴스별로 50개씩
똑같이 나누어 주고 싶을 것이고, 차후에 다시50개의 새로운 클라이언트가
접속한다면다시각각25개씩나누어주어언제나공평하게부하를유지하고
싶을것이다.
하지만, 이제까지의예제와같이TNS alias에서load_balance=off로설
정한경우에는어느클라이언트가어느인스턴스로접속할지수동으로모두
설정해 주어야 하는 번거로움이 있었다. 만일 이것이 자동으로 된다면? 즉,
O R A C L E D E V E L O P E R
106 ORACLE KOREA MAGAZINE
100개의 클라이언트가 무작위로 접속할 때 자동으로50개씩 나누어진다면
훨씬더편리할것이다.
사실 Oracle9i Real Application Clusters가 나오기 이전에 Oracle
Parallel Server를 사용하는 고객들은 로드 밸런싱을 잘 사용하지 못했다고
할수있다. 왜냐하면, Oracle Parallel Server에서발생하는핑(ping) 현상으
로인해보통불가피하게노드별로데이타를분할하여데이타베이스를구성
하므로, 업무별/지역별로클라이언트를나누어특정인스턴스를지정해서접
속해야했기때문이다.
하지만, Oracle9i Real Application Clusters에서완벽하게이루어지는
Cache Fusion의 기능으로더 이상 데이타의분할이 필요 없게 되었으므로,
클라이언트는Oracle9i Real Application Clusters로구성된데이타베이스
내의어떤인스턴스에접속하더라도성능에는아무런영향을주지않는다.
오라클의로드밸런싱설정은다음두가지가있다.
. 클라이언트로드밸런싱: 클라이언트가같은SERVICE_NAME을사용하
는인스턴스들중에무작위로선택하여접속하는방법이다.
. 리스너(커넥션) 로드 밸런싱 : Oracle9i Real Application Clusters의새
로운기능으로리스너가각인스턴스의부하에대한정보를가지고있어서항
상부하가덜걸린인스턴스쪽으로클라이언트를접속시켜주는방법이다.
그러면이제각각의방법을어떻게구현할수있는지차례로살펴보자.
클라이언트 로드 밸런싱
앞서설정했던BASIC메소드의TAF 설정을다음과같이수정해보자.
RAC_TAF =
(description=
(load_balance=on)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic))
)
)
다른것은그대로둔채로load_balance 부분만on으로설정하면클라
이언트로드밸런싱이구성된다. 이제반복적으로접속하여결과를보도록하
자.
SQL> conn scott/tiger@rac_taf
Connected.
SQL> select userenv('instance') from dual;
USERENV('INSTANCE')
--------------------------
2
SQL> conn scott/tiger@rac_taf
Connected.
SQL> select userenv('instance') from dual;
USERENV('INSTANCE')
--------------------------
1
위와같이클라이언트는인스턴스를바꿔가며RAC1, RAC2에무작위로
접속하는 것을 볼 수 있다. 라운드로빈(round-robin) 방식이 아닌 무작위
(random) 방식이므로, 특별한패턴을찾을수는없지만, 접속횟수가많아질
수록 균일하게 분배되는 것을 알 수 있을 것이다. 즉, 예제와 같이 2노드의
Oracle9i Real Application Clusters 환경에서100회반복하여접속한다면,
거의50:50으로나누어지는것을확인할수있을것이다.
클라이언트로드밸런싱을하는경우특별히동적등록이필요하지는않
으나, 예제와같이TAF와함께사용하는경우에는반드시동적등록이구성
되어있어야한다.
리스너(커넥션) 로드 밸런싱
최초에RAC1 인스턴스에는100개의클라이언트, RAC2 인스턴스에는10개
의클라이언트가접속되어있었다고가정하자. 이후에다시100개의새로운
클라이언트를클라이언트로드밸런싱을설정하여접속시킨다면? 결과는새
로운100개의클라이언트들은50:50으로균일하게분배되어결국최종적으
로는RAC1인스턴스는150개, RAC2 인스턴스에는60개의클라이언트가붙
을것이다.
이렇게되면RAC1인스턴스입장에서는불공평한결과가될수있다. 즉
RAC2인스턴스가훨씬더여유가있다는것을미리알아서, 새로이들어오는
100개의클라이언트를5:95로분배하여결국105:105가되도록해준다면각
각의인스턴스입장에서는언제나공평한결과를만들수있다.
바로이것이Oracle9i Real Application Clusters에서새로등장한리스
너(커넥션) 로드 밸런싱이며, 이것을 위해서는 서버쪽의 tnsnames.ora와
init.ora에다음과같은설정을추가해야한다. krrac1의tnsnames.ora에다
음과같은항목을추가해보자.
LISTENER_RAC2 =
(description=
(address=(protocol=tcp)(host=krrac2)(port=1521))
)
그리고SYSDBA사용자로다음과같이remote_listener 파라미터값을
변경해보자.
SQL> alter system set remote_listener='LISTENER_RAC2';
System altered.
이제krrac2(krrac1이아님)의리스너를확인해보자. <리스트5>와같이
RAC 서비스에기존에등록되어있던RAC2 인스턴스와함께, RAC1 인스턴
스도추가로동적으로등록되어있는것을볼수있다.
<리스트5> 리스너로드밸런싱에서리스너확인
krrac2|/data/oracle> lsnrctl services
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 14-JUL-2003 15:29:55
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac2)(PORT=1521)))
Services Summary...
Service "RAC" has 2 instance(s).
Instance "RAC1", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0 state:ready
REMOTE SERVER
(DESCRIPTION=(address=(protocol=tcp)(host=krrac1)(port=1521)))
Instance "RAC2", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:25 refused:0 state:ready
LOCAL SERVER
The command completed successfully
그러면, 이제 krrac2의 tnsnames.ora, RAC2 인스턴스의
remote_listener 값을마찬가지로올바르게설정했다면krrac1의리스너에
도<리스트 6>과같이RAC1, RAC2 인스턴스가모두등록되어있는것을확
인할수있을것이다.
<리스트6> 리스너로드밸런싱에서인스턴스의등록확인
krrac1|/data/oracle> lsnrctl services
LSNRCTL for Solaris: Version 9.2.0.3.0 - Production on 14-JUL-2003 15:33:52
Copyright (c) 1991, 2002, Oracle Corporation. All rights reserved.
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=krrac2)(PORT=1521)))
Services Summary...
Service "RAC" has 2 instance(s).
Instance "RAC1", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:0 refused:0 state:ready
REMOTE SERVER
(DESCRIPTION=(address=(protocol=tcp)(host=krrac1)(port=1521)))
Instance "RAC2", status READY, has 1 handler(s) for this service...
Handler(s):
"DEDICATED" established:25 refused:0 state:ready
LOCAL SERVER
The command completed successfully
앞서설명한동적등록이무엇을의미하는가를기억한다면, 여기서각각
의인스턴스가remote_listener 파라미터를사용함으로써상대방노드의리
스너에자신의상태를지속적으로업데이트해주고있다는것을눈치챌수있
다.
즉, 예제와같이리스너(커넥션) 로드밸런싱을사용하는경우클라이언
트는접속할때다음과같은과정을거치게된다.
1. 클라이언트는 일단 TNS alias의 address_list의 첫 번째 항목인 krrac1의
1521 포트로기동된리스너에컨택한다.
2. krrac1의 리스너는RAC1, RAC2 인스턴스가 모두 등록되어 있으며, 각인
스턴스는 자신이 서비스가 가능한 상태인지의 여부와, 자신이 가지고 있는
부하(접속해 있는 클라이언트의 개수)를 지속적으로 업데이트해 주고 있으
므로, 1에서리스너에컨택한클라이언트는RAC1과RAC2 중어느것이적
은수의클라이언트를가지고있는지알수있다.
3. 만일 RAC1의 클라이언트 수가 적다면, 로컬 노드(krrac1)에서 Oracle
Server Process(Foreground Process)를만들어서커넥션을맺어준다.
4. 만일RAC2의클라이언트수가적다면, address_list의다음에나오는항목
(리모트 노드 : krrac2의 1521 포트)에 등록되어 있는 리스너로 리다이렉트
시켜준다.
5. krrac2의리스너는이제Oracle Server Process(Foreground Process)
를만들어서 커넥션을맺어준다.
따라서, 리스너의서비스에remote_listener를사용하여Oracle9i Real
Application Clusters의 모든 인스턴스가 등록되어 있기만 하다면, 언제나
공평한분배(로드밸런싱)가이루어질수있다.
설정후테스트는다음과같이해볼수있다.
1. RAC1 인스턴스에만로드밸런싱을사용하지않고미리상당수의커넥션을
맺어놓는다(이를테면10개라고하자.)
2. 이제 RAC_TAF TNS alias를 가지고 반복적으로 접속해 보자. 10개까지
는 RAC2에만 접속되어 각 인스턴스에 10개씩의 클라이언트가 만들어질
것이다.
3. 이어서 지속적으로 RAC_TAF TNS alias를 가지고 반복적으로 접속해 본
다면, 이제는 각 인스턴스에 거의 번갈아서 접속하면서 클라이언트 개수의
총합이언제나50:50으로유지되는것을볼수있을것이다.
마지막으로 주의할 점은, 리스너(커넥션) 로드 밸런싱은 항상 클라이언
트로드밸런싱을오버라이드하므로, remote_listener가설정되어리스너에
여러 인스턴스가 등록되어 있는 경우, 아래와 같이 TNS alias에서 클라이언
트로드밸런싱을사용하지않더라도, 리스너(커넥션) 로드밸런싱은계속이
루어진다는사실이다. 즉, 아래와같이TNS alias를설정한경우에로드밸런
싱이 일어나고 있다면, 일단 remote_listener가 설정되어 있는지 우선 확인
해보도록하자.
RAC_TAF =
(description=
(load_balance=off)
(failover=on)
(address=(protocol=tcp)(host=krrac1)(port=1521))
(address=(protocol=tcp)(host=krrac2)(port=1521))
(connect_data=
(service_name=RAC)
(failover_mode=(type=select)(method=basic))
)
remote_listener 값은Oracle9i Database Release 2(9.2)부터는아래
와같이동적으로해제할수있다.
SQL> alter system set remote_listener='';
System altered.
이제까지로드밸런싱을설명하면서계속TAF를예로들었지만, CTF 설
정(failover_mode 부분제고)으로도똑같은로드밸런싱을구현할수있으
며, 예제와똑같은테스트를할수있다.
난공불락의Oracle9i Real Application Clusters
필자가Oracle9i Real Application Clusters를도입하고자하는독자들에게
하고싶은말은, 일단싱글인스턴스환경에서시스템을문제없이사용해왔다
면, Oracle9i Real Application Clusters로의전환이후에도문제없는시스
템을 유지할 수 있으며, 나아가 오라클이 자랑하는 ‘난공불락 Oracle9i Real
Application Clusters’의놀라운기능을마음껏누릴수있다는것이다.
마지막으로필자가3회의연재를통해언급한몇가지주의사항을다시
한번정리하며끝을맺기로한다.
. 싱글 인스턴스로 운영중이던 애플리케이션은 Oracle9i Real Application
Clusters로 전환 시 Cache Fusion이 완벽하게 작동하므로 별도의 데이타
분할이필요없다.
. Oracle9i Real Application Clusters에서 고속 인터커넥트는 Cache
Fusion을위해필수이며, HA로구성되어있는것이바람직하다.
. 싱글 인스턴스 환경에서 튜닝 되지 않은 SQL들은 Oracle9i Real
Application Clusters 환경에서 더욱 성능이 악화될 수 있으니, Oracle9i
Real Application Clusters 전환 전에 애플리케이션을 반드시 점검하도록
하자.
. global cache cr request가과다하게보이는경우, 무엇보다도SQL 튜닝이
되어있는지먼저확인하고, 읽기액세스가대부분인테이블스페이스에한하
여gc_files_to_locks 파라미터를신중하게고려해본다.
. 페일오버설정은각장애유형별로철저히테스트해보아야하며, 애플리케이
션분할이되어있지않다면로드밸런싱을하는것이바람직하다.