My Books

My Slides

rss 아이콘 이미지

[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


 

티스토리 툴바