본문 바로가기
  • 읽고보고쓰고
PROGRAMMING/Database

JEUS JDBC

by 체리그루브 2015. 6. 6.
728x90

웹 어플리케이션은 정보 저장이 필요할 때 주로 데이터베이스(Database, 이하 DB)를 이용한다. 이를 위해 JEUS와 같은 WAS (Web Application Server)는 어플리케이션이 DB로 접근할 수 있는 통일된 방법을 제공해야 한다. 이러한 통일된 DB 접근을 위해 만든 표준이 바로 JDBC(Java Database Connectivity) 표준이다. JDBC 표준은 어플리케이션이 DB 커넥션을 사용하는 방법에 대해 기술하고 SQL 작업을 하기 위한 API를 제공하고 있다. 표준에 관한 자세한 내용은 Sun JDBC 페이지(http://java.sun.com/javase/technologies/database)를 참고하도록 한다.

JEUS에서는 어플리케이션의 원활한 DB 사용을 위해 커넥션 풀(Connection Pool)과 여러 부가 기능들을 제공한다. 이번 장에서는 JEUS에서 제공하는 커넥션 풀 및 부가 기능들에 대해 설명하고 그 사용법에 대해 알아보도록 한다.

JEUS는 JDBC 인증을 받은 드라이버들을 지원한다. 인증된 드라이버의 타입이나 그 종류는 Sun의 'Types of JDBC technology drivers' (http://java.sun.com/products/jdbc/driverdesc.html) 문서에서 찾을 수 있다. JEUS의 JDBC 환경구성은 어떤 벤더의 DB를 사용하느냐에 따라 환경 구성이 서로 다를 수 있다. 이는 각 드라이버마다 각자 요구하는 속성이 다르기 때문이므로 각 벤더의 JDBC 드라이버 매뉴얼을 참고해야 한다.

아래의 [그림 9.1] 은 JEUS JDBC 커넥션 풀링의 전체적인 구조를 보여준다.


아래는 데이터 소스들의 4가지 타입들을 간략하게 정리하였다.

지금까지 JEUS 설정에서 제공하는 다양한 데이터 소스 형식을 살펴보았다. 데이터 소스에는 다양한 종류가 있으면서 각각 장단점을 가지고 있다. 그러므로 어플리케이션에서 필요한 것이 무엇인지 확인하고, 최적의 성능과 각각의 상황을 위해 적당한 타입을 사용해야 한다.

JEUS 레벨에서 RAC 인스턴스 간의 Failover & Failback을 제공하기 위해서 클러스터 데이터 소스를 제공한다. RAC는 Real Application Cluster의 약자로 오라클에서 제공하는 DB 클러스터링 기능이다. RAC에 관한 자세한 내용은 오라클의 문서를 참고하기 바란다.

클러스터 데이터 소스는 근본적으로는 하나의 JNDI 이름을 가진 데이터 소스 인스턴스이다. 이 인스턴스는 어플리케이션의 요청을 우선 주 RAC 인스턴스로 전달시켜주는 역할을 한다. 만약 주 인스턴스가 다운되었을 경우, 백업 RAC 인스턴스가 선택되어서 요청 사항을 처리하게 된다. 어플리케이션에서는 단지 하나의 데이터 소스만 보게 되므로 장애복구가 투명하게 처리된다. [그림 9.2]


그리고 오라클 JDBC 드라이버 레벨에서 제공하는 CTF(Connect Time Failover)보다는 JEUS의 클러스터 데이터 소스를 사용하길 권장한다. 오라클 CTF의 경우에는 커넥션 별로 Failover를 하기 때문에 데이터 소스 전체가 문제가 생겼을 경우 풀에 있는 모든 커넥션마다 Failover를 해야 하기 때문에 성능이 떨어진다. 그러나 JEUS 클러스터 데이터 소스에서는 데이터 소스에 문제가 생긴 것을 감지하면 데이터 소스 단위로 Failover를 하므로 더 효율적이며, 자동으로 Failback을 하는 기능도 제공한다.

JEUS6 fix#3부터는 기본적으로 Failback을 지원하므로 이를 위한 설정이 반드시 필요하다. 클러스터 데이터 소스 설정에 관한 내용은 9.3.5절. “클러스터 데이터 소스 설정”를 참고하기 바란다.

참고

JEUS의 클러스터 데이터 소스를 사용하는 방식과 오라클 JDBC 드라이버에 RAC 속성을 설정하는 방식은 서로 동작이 다르다는 점에 주의해야 한다. 전자는 Failover를 JEUS가 처리하는 것이기 때문에 각 RAC 인스턴스의 FAIL 여부를 감지하기 위해서 check-query와 check-query-period를 설정해야 한다. 그러나 후자는 드라이버가 Failover를 담당하게 되므로 check-query가 필수적인 것은 아니다.

JEUSMain.xml 에 데이터 소스를 설정할 수 있다. javax.sql.DataSource의 속성들은 각 드라이버별로 다르기 때문에 사용하기 원하는 드라이버의 특성을 파악하고 그 특성에 맞게 설정을 해야 한다. 각 태그들의 전체 리스트는 부록 E. “참고 자료”에 소개된 XML Reference에서 찾을 수 있다. 또한 JDBC 구성 예제들은 부록 B. “주요 벤더의 JDBC Data Source 구성 예”를 보기 바란다.

아래의 XML 태그들은 <resource><data-source>...<database> XML 태그의 하위 태그로 이용할 수 있다.

주의

data-source-name, service-name, network-protocol, driver-type 등 특정 JDBC 드라이버에 의존적인 프로퍼티들은 커스텀 프로터티 설정으로 대체하길 권장한다.

예제 (Oracle):


앞서 설명한 기본 설정으로 부족할 때 <database>구성에 커스텀 프로퍼티를 추가하여 해당 프로퍼티를 가진 DB 드라이버를 사용할 수 있다. 각각의 새로운 속성을 추가를 위해 세가지 항목을 정의함으로써 사용할 수 있다. 각각의 DB 마다 요구하는 프로퍼티와 그 값이 다르므로 각 벤더의 JDBC 드라이버 매뉴얼에서 필요한 프로퍼티를 찾도록 한다.

  • 속성의 name

  • 속성의 type

    java.lang.String, 원시 타입(Primitive type)의 래퍼 클래스(Ex. java.lang.Integer), java.util.Properties가 올 수 있다.

  • 속성에 문자열을 줌으로써 value를 부여할 수 있다.


<property> 태그는 위의 예처럼 추가된다. 위의 예처럼 프로퍼티가 지정이 되면 JEUS는 벤더의 JDBC 드라이버에 setPortNumber라는 메소드를 호출하게 된다. 그러므로 사용자는 각 벤더의 매뉴얼 등을 참고하여 속성을 알맞게 설정하도록 한다.

위에서 설명된 데이터 소스를 적절히 구성해 주었다면, JEUS를 재시작 해주어야 데이터 소스를 어플리케이션에서 사용할 수 있다.

각 데이터 소스는 향상된 성능을 위하여 커넥션 풀 설정을 할 수 있다. 이는 JEUSMain.xml<database> 태그 아래 <connection-pool>을 사용하여 구성된다.


어플리케이션이 JDBC 커넥션 요청을 했을 때(getConnection method) 특정 select 쿼리를 보내서 커넥션의 상태를 점검(validation)하는 기능이다. JDBC 커넥션의 내부적인 에러로 인한 끊김, 방화벽에 의한 소켓 끊김 현상 등을 체크할 때 유용하다. 점검이 실패하면 물리적 커넥션을 새로 만들어서 그에 대한 핸들을 어플리케이션으로 리턴해 준다. 만약 RAC를 위한 데이터 소스 클러스터링을 사용하는 경우 이것을 반드시 설정해야 한다.

Check-query 기능은 크게 두 가지로 설정할 수 있다. 첫째로 단순히 설정상의 <check-query> 태그에 쿼리문을 넣는 방법이 있고, <check-query-class> 태그를 이용하여 기능을 확장할 수도 있다.

Check-query를 위한 쿼리문은 DB에 업데이트를 가하는 명령이 아닌 단순히 쿼리만을 위한 명령어를 넣어야 한다. 그렇지 않을 경우 Check-query를 위해 DB 락을 잡기 때문에 이후 업데이트를 위한 작업들이 원활히 수행되지 않을 수도 있다.


Check-query를 수행했을 때 DB 서버가 응답을 안 줘서 드라이버가 계속 기다리는 상황이 발생할 수 있다. 이런 경우를 피하기 위해 Check-query에 대해서 타임아웃을 줄 수 있다. 이것은 JDBC에서 제공하는 'statement query timeout' 기능을 이용하는 것이다. 설정값은 밀리세컨드이며, 1000 밀리세컨드보다 적을 경우 결국 0이 세팅되므로 주의하기 바란다.


만약 Check-query가 너무 잦아져서 오버헤드가 발생한다면 <non-validation-interval> 설정을 고려하길 권한다. 이는 Check-query를 수행할 때의 시각과 맨 마지막에 커넥션을 사용한 시각과의 차이가 설정한 인터벌 내에 있다면 Check-query를 하지 않도록 하는 설정이다. 예를 들어 Non-Validation-Interval을 5초(5000 ms)라고 설정했을 때, 어떤 커넥션을 풀에서 꺼내서 마지막에 사용했던 시간이 아직 5초가 지나지 않았다면 그 커넥션이 유효하다고 가정하고 Check-query를 수행하지 않는 것이다.


사용자는 Check-query가 실패했을 때 해당 커넥션 풀에 있는 나머지 커넥션들에 대한 destroy 정책을 결정할 수 있다. 정책은 아래와 같다.

만약 정책을 'AllConnections'로 했을 경우에는 Check-query가 실패하자마자 바로 커넥션들을 버리는 것이 아니라 한 번 더 커넥션을 풀에서 꺼내서 Check-query를 시도해 본다. 그마저도 실패하면 비로소 풀에 있는 모든 커넥션들을 버린다.


그리고 Check-query를 추가적으로 더 하도록 설정하고 싶을 경우에는 <check-query-retrial-count>를 이용해서 설정할 수 있다.

Check-query 클래스는 Check-query 기능을 사용자가 확장할 수 있도록 한다. 응용 프로그램 개발자나 사용자는 위에서 제시한 jeus.jdbc.connectionpool.JEUSConnectionChecker interface를 구현함으로써 기능의 확장을 도모할 수 있다.


만약 Check-query class가 지정이 되지 않은 상태라면, JEUS는 지정된 쿼리문만을 이용하여 Check-query를 수행하게 된다. 즉 Check-query class의 사용은 선택을 할 수 있으며, 단순히 쿼리문을 이용하는 것이 아닌 특별한 작업이 필요한 경우에만 사용하도록 한다.

....
   Connection conn = dataSource.getConnection();
   PreparedStatement stmt = conn.prepareStatement(sql);
   ....
   stmt.close();
   conn.close();
....

PreparedStatement는 미리 SQL을 파싱해놓은 인스턴스를 어플리케이션 입장에서 계속 재활용해서 사용할 수 있으므로 매번 드라이버가 SQL을 파싱하기 위해 들이는 오버헤드를 줄일 수 있다. 그런데 이러한 PreparedStatement 역시 커넥션을 새로 얻을 때마다 SQL 파싱 작업을 해야 하므로 커넥션 요청(getConnection & close)이 빈번하게 이뤄지는 경우에는 PreparedStatement 인스턴스를 생성하는 것 역시 큰 오버헤드가 될 수 있다. 따라서 JEUS에서는 이런 오버헤드를 줄이기 위해 Statement Caching 기능을 제공한다. 이것을 사용하면 물리적 커넥션 별로 SQL 문장을 키로 하여 PreparedStatement 객체를 저장해놓고 어플리케이션이 PreparedStatement를 요청할 경우에 파라미터로 넘어온 SQL을 보고 미리 만들어진 것이 있으면 그것을 리턴해준다.

그런데 Connection 인스턴스에서 PreparedStatement를 만들기 때문에 그 Connection 인스턴스를 닫아버리면(close) 해당 PreparedStatement 인스턴스 역시 무효로(invalid) 된다. 따라서 어플리케이션이 커넥션을 닫았다고 하더라도 실제로 WAS에서는 이 커넥션을 계속 열어둔 채로 재활용하도록 되어 있다. 그래야만 PreparedStatement 인스턴스를 계속 재활용 할 수 있기 때문이다.

주의

어플리케이션은 Statement Caching의 제약사항을 반드시 숙지해야 한다. 즉, 커넥션을 항상 열어둔 채로 사용하기 때문에 커넥션을 닫았을 때 드라이버가 해주는 클리어 작업이 이뤄지지 않는다. 예를 들어 Oracle JDBC 드라이버의 경우, auto-commit을 false로 해놓고 사용하다가 commit이나 rollback을 하지 않고 커넥션을 닫으면 무조건 commit을 하도록 되어 있는데 이런 처리가 되지 않는다는 것이다. keep-connection-handle-open 옵션 또한 같은 제약사항이 있으므로 주의하기 바란다.

일반적으로 XA 데이터 소스가 사용 되면, 대부분 트랜잭션으로 묶여 작업이 이루어진다. 하지만 일부의 경우에는 트랜잭션이 시작되기 전이나, 끝난 후에 커넥션을 가져다 쓰는 경우가 있을 수 있다. 이런 상황에서는 트랜잭션과 무관하게 커넥션이 사용되므로 커넥션 풀 형식의 데이터 소스에서 가져온 커넥션과 동작에 있어 아무런 차이가 없게 된다.

그런데 Oracle, DB2 등의 JDBC 드라이버에서는 XA 커넥션을 트랜잭션 없이 사용도 하고 트랜잭션에 연동도 하면서 사용하다 보면 XA를 시작할 수 없는 예외가 발생한다. 정확한 원인은 알 수 없기 때문에 이를 피해 가기 위해서 위임 데이터 소스를 사용할 수 있다.

위임 데이터 소스(Delegation Datasource)는 XA 형식으로 지정된 데이터 소스가 트랜잭션과 무관한 곳에서 커넥션 요청을 받을 경우 이용하게 되는 데이터 소스이다. 이 상황에서 사용자가 커넥션 요청을 할 경우 XA 데이터 소스는 위임 데이터 소스로 지정된 커넥션 풀 데이터 소스에서 커넥션을 가져와 사용자에게 넘겨주게 된다.

이 기능을 사용하기 위해서는 우선 XA 데이터 소스와 같은 DB에 대한 커넥션 풀 데이터 소스를 지정한다. 그리고 <delegation-datasource> 태그 내부에 설정한 커넥션 풀 데이터 소스의 JNDI 이름을 넣어주면 된다.

앞서 <delegation-datasource>, <dba-timeout>에서 설명한 것처럼 DBA 위임 데이터 소스는 Connection에 대응하는 DB Session을 강제로 정리해줘야 할 필요가 있을 때 사용한다. ConnectionPool에서 Connection을 얻어간 뒤 오랜 시간동안 Pool로 반납되지 않으면 해당 Connection이 DB에 부하를 주거나 장애를 일으킬 것으로 판단하고 강제로 DB를 정리를 하고자 사용하던 기능이다. JEUS6 Fix#6에서는 Webadmin을 통해서 DB Connection 강제 정리 명령을 내릴 때도 DBA 위임 데이터 소스가 설정되어 있다면 이를 이용해서 DB에 Session Kill명령을 내리도록 하였다. 기본적으로 이 기능은 DB에 직접 operation을 가하는만큼 사용시에 주의가 필요하지만 아래에서 dba-timeout을 설정하면 어떻게 작동하는지 간략하게 설명하겠다.

우선 사용하는 데이터 소스 외에 커넥션 풀 형식의 새로운 데이터 소스를 설정한다. 그 데이터 소스 이름이 DBKiller라고 한다면 사용하고 있는 데이터 소스에 다음과 같이 설정해준다.


이렇게 설정이 되어있으면, 다음과 같은 동작을 한다. 만약 현재 사용하는 데이터 소스에서 얻어진 커넥션이 <dba-timeout> 태그에 지정 된 60초(단위가 msec이므로) 안에 반납이 되지 않으면, JEUS JDBC는 DBKiller 데이터 소스에 반납되지 않은 커넥션의 세션 id를 죽이라는 kill 명령을 내린다. 그렇게 되면 DBKiller 데이터 소스는 해당 커넥션을 강제로 닫아주게 되게 된다. 하지만 응용 프로그램이 명시적으로 close 명령을 내리지 않으면 해당 Connection은 active인 상태로 남아있게 된다. close를 호출하면 Connection을 버리고 새로 Connection을 맺어서 Pool에 넣어둔다.

이 기능을 사용하기 위해서는 DB가 이 기능을 지원해야 한다. JEUS에서는 단순히 해당 DB에 세션 제거를 요청하는 쿼리를 요청하고, DB가 해당 쿼리를 받아 동작을 수행한다. 자세한 내용은 DB 벤더에서 제공된 매뉴얼을 참고하여 기능의 지원 여부를 따져보도록 한다. 또한 DBA 위임 데이터 소스는 실제 DBA 대상이 되는 데이터 소스와 같은 DB에 설정이 되어있어야 한다.

경고

이 기능은 예전 JDBC 스펙에서는 select query 등이 너무 오래 걸릴 때 그것을 끊어줄 방법이 없어서 사용한 방법인데 현재는 statement query timeout 등이 있으므로 이 기능을 사용할 필요가 없다. 특히 세션 킬 이후에 rollback이 되지 않기 때문에 XA 데이터 소스에는 설정해서 사용하면 안 되고 트랜잭션 타임아웃을 적절하게 세팅해서 사용하길 권장한다.

앞서 보았듯이, JEUS 차원에서 RAC 인스턴스 간의 장애 복구(failover and failback)를 제공하기 위해서 클러스터 데이터 소스를 설정할 수 있다. 이 설정은 <resource> <data-source> <cluster-ds> 태그를 사용해서 설정한다. 이 태그가 포함하는 설정은 다음과 같다.

  • export-name: 클러스터 데이터 소스의 JNDI 이름.

  • use-failback: true 혹은 false 값으로, failback 기능을 사용할 것인지 선택하는 옵션이다. 이전에는 failover만을 지원했기 때문에 호환성을 위해서 만든 옵션이다. 기본값은 true.

  • is-pre-conn: true 혹은 false 값으로, true이면 클러스터 데이터 소스에 참여하는 모든 데이터 소스의 커넥션을 미리 연결시켜 놓는다. 이렇게 될 경우 failover 성능은 향상될 수 있으나, 반대로 시스템 리소스가 많이 이용된다는 단점이 있다. 기본값은 false.

  • data-source: 클러스터 데이터 소스에 포함되는 데이터 소스의 export name을 적어준다.

리스트의 첫번째가 주 RAC 인스턴스가 되고, 이것이 다운되면 다음 인스턴스가 선택된다. 다음의 설정 예제의 경우 처음에는 RAC1 데이터 소스에서 커넥션을 가져오고 커넥션을 가져오는 도중 Exception이 발생할 경우(Wait timeout인 경우는 제외) RAC2 데이터 소스를 사용하게 된다.


JEUS 6 fix#3부터는 자동으로 Failback을 해주는 기능이 포함된다. 클러스터 데이터 소스에서 Failback을 하기 위해서는, 참여하는 모든 데이터 소스에 반드시 check-querycheck-query-period를 설정해줘야 한다. 예제에서 주 데이터 소스는 RAC1이고 백업 데이터 소스가 RAC2이다. 만약 RAC1이 죽었거나 문제가 생겼을 경우에는, 어플리케이션이 커넥션을 가져갈 때(getConnection) check-query에 의해 이를 감지하게 되며 Failover를 통해서 RAC2 데이터 소스를 사용하게 된다. 그리고 RAC1 데이터 소스가 살아났는지 check-query-period에 설정한 주기마다 체크한다. RAC1 데이터 소스이 살아난 후부터는 모든 커넥션 요청이 자동으로 RAC1 데이터 소스로 가게 된다.

만약 예전처럼(JEUS 6 fix#2 이하) Failover만을 사용해야 할 경우에는 <cluster-ds><use-failback>을 false로 할 수 있다. 그리고 수동으로 Failback 명령을 내릴 수 있는데 이에 대해서는 JEUS Reference Book에서 controlcds 명령을 참조하기 바란다.

그리고 check-query 실패시 풀에 있는 커넥션에 대한 destroy 정책을 AllConnections로 설정하기 바란다. 그렇지 않으면 만약 RAC1이 죽고 RAC2로 Failover 되었을 경우 RAC1에는 이미 끊어진 커넥션들이 풀에 계속 남아있게 된다. 물론 주기적인 check-query에 의해서 정리가 되지만 Failover가 이뤄지는 시점에 끊어진 커넥션들이 정리가 되는 것이 좀더 바람직하기 때문이다.


JEUS의 주 콘솔 툴인 jeusadmin을 이용하여 DB 관련 설정 및 동작을 모니터링 하거나 제어할 수 있다.

사용 예제:

[blah@johan:/opt/jeus/bin] ./jeusadmin johan [options]

위의 명령을 사용하여 JEUS 노드에 접속을 한다. 그 후 커넥션 풀을 제어하기 위해, 다음과 같이 명령을 내릴 수 있다.

johan>disableds -con johan_container1 datasource1

위의 명령어는 johan_container1에 설정 되어 있는 'datasource1'이라 명명된 커넥션 풀을 불능상태로 만들 때 사용된다.

johan>dsinfo -con johan_container1

위 명령은 johan_container1에 설정 된 데이터 소스들의 정보를 보기 위한 명령이며, 아래와 유사한 정보를 볼 수 있다.

======================================================================
Connection pool information for engine container 'johan_container1'
--------------------------------------------------------------------
|        name | min | max | act | idle | disp | tot | wait |  work |
--------------------------------------------------------------------
| datasource1 |   3 |   4 |   0 |    3 |    0 |   3 | true | false |
| datasource2 |   3 |   5 |   0 |    0 |    0 |   0 | true | false |
| datasource3 |   3 |   6 |   0 |    1 |    0 |   1 | true | true  |
--------------------------------------------------------------------
disp : disposable connection, tot(total) = act(active) + idle + disp
======================================================================

dsinfo 명령에서의 "work"필드는 풀이 생성되지 않았거나 비활성 상태임을 나타낸다. idle 커넥션이 하나도 없는 경우에는 아직 생성되지 않은 풀이라고 보면 되고 idle 커넥션이 존재하는 경우에는 비활성화된 풀로 보면 된다.

만약 생성된 커넥션 풀만 보고 싶다면 -active 옵션을 주면 된다.

풀을 활성화시키기 위해서 아래의 명령어를 적용한다.

johan>enableds -con johan_container1 datasource1

jeusadmin을 통해서 connection pool을 처음 생성하거나 풀에 있는 커넥션을 모두 비우고 새로운 커넥션으로 채워넣을 수도 있다.

처음 생성할 경우에는

johan>createds -con johan_container1 datasource2

와 같은 명령을 내리면 된다. -con 옵션을 주지 않으면 모든 엔진 컨테이너의 커넥션을 풀을 생성한다. 만약 container.name 프로퍼티가 설정되어 있다면 그 설정으로 지정된 엔진 컨테이너(들)의 커넥션 풀(들)만 생성한다.

현재 풀에 있는 커넥션을 모두 버리고 새로운 커넥션으로 채워넣고 싶다면 (DB를 리붓했거나 비정상적 종료를 해서 풀에 있는 커넥션들이 모두 의미없는 상태가 된 경우 등)

johan>refreshds -con johan_container1 datasource3

와 같은 명령을 내리면 된다. 엔진 컨테이너에 해당하는 옵션은 createds 명령과 같다.

jeusadmin에서 하나의 엔진 컨테이너에 구성된 JDBC 커넥션 풀을 모니터링 하기 위해서 'dsinfo'를 사용할 수 있다. jeusadmin 프롬프트에서 이 명령어는 아래의 리스트와 유사한 정보를 제공할 것이다.

johan>dsinfo -con johan_container1 datasource1
========================================================================
Connection pool information for engine container 'johan_container1'
-------------------------------------------------------------------
|        name | min | max | act | idle | disp | tot | wait | work |
-------------------------------------------------------------------
| datasource1 |   1 |   1 |   0 |    1 |    0 |   1 | true | true |
-------------------------------------------------------------------
disp : disposable connection, tot(total) = act(active) + idle + disp
========================================================================

이 출력창에 대한 각 필드의 설명이다:

  • name : DB 풀의 export name

  • min : 풀안에서 유지되는 커넥션의 최소 크기(항상 이 값으로 유지되지 않을 수 있으며 리사이즈 주기에 의해 유지됨)

  • max : 풀안에서 유지되는 커넥션의 최대 크기

  • act : 어플리케이션이 사용하고 있는 커넥션의 수

  • idle : 현재 풀에 들어있는 커넥션의 수

  • disp : 한번 사용하고 버리는 커넥션의 총 갯수

  • tot : DB 커넥션의 총 수 (active + idle+disposable connection)

  • wait: 풀에 커넥션이 비었을 경우, 쓰레드를 기다리게 할 것인지를 결정한다. "true"일 경우 기다리게 하고, "false"일 경우 풀과 상관 없는 커넥션을 만들어준다.

  • work: 만약 DB 풀이 활성화 상태이면 "true"이고 비활성화이거나 아직 생성되지 않은 상태이면 "false"이다.

만약 생성된 커넥션 풀만 보고 싶다면

  • -active : 생성된 커넥션 풀만을 보여준다. 인자는 없다.

  • -k : 몇 번 정보를 보여줄지 결정한다. (e.g. -k 20)

  • -i : 몇 초에 한번씩 정보를 보여줄지 결정한다. 인자값의 단위는 초(sec)이다. (e.g. -i 1)

-k 옵션은 -i 옵션이 반드시 필요하며 -i 옵션만 지정했을 경우에는 모니터링 정보 출력을 무한히 반복하게 되는데 엔터키를 두 번 입력해서 끝낼 수 있다.

또한 dsconinfo를 사용하여 각각의 데이터 소스 별로 현재 커넥션의 상태를 파악하거나 관련 통계를 볼 수 있다.

johan>dsconinfo -con johan_container1 datasource1
===============================================================
Connection information list for the engine container[johan_container1]
---------------------------------------------------------------
|            id | state | state-time(ms) | use-count |   type |
---------------------------------------------------------------
| datasource1-1 |  idle |          10000 |         0 | pooled |
---------------------------------------------------------------
===============================================================

dsconinfo 명령은 데이터 소스의 이름을 인자로 받고 해당 풀에 있는 커넥션들의 정보를 보여준다.

  • id : 해당 컨테이너의 데이터 소스 내에서 각 connection 별로 붙인 고유한 값이다.

  • state : 커넥션의 상태를 나타내며 active와 idle로 나뉜다. active일 경우 현재 사용중인 커넥션을 의미한다.

  • usecount : open, close 짝이 몇 번 일어났는가를 의미한다.

  • state time : 커넥션이 현재 상태로 바뀐 후 지속된 시간을 의미한다. 예를 들어, 'datasource1-1' 커넥션의 경우 유휴(idle) 상태로 10초간 있었음을 알 수 있다.

  • type : 풀링된 커넥션인지 disposable 커넥션인지 구분할 수 있다.

이와 더불어 두 명령어 모두 -k와 -i 옵션을 사용할 수 있다.

  • -k : 몇 번 정보를 보여줄지 결정한다. (e.g. -k 20)

  • -i : 몇 초에 한번씩 정보를 보여줄지 결정한다. 인자값의 단위는 초(sec)이다. (e.g. -i 1)

-t 옵션을 사용하면 커넥션을 가장 마지막에 사용한 쓰레드의 이름을 알 수 있다.

johan>dsconinfo -con johan_container1 -t datasource1
==============================================================================
Connection information list for the engine container[johan_container1]
------------------------------------------------------------------------------
|            id |  state | state-time(ms) | use-count |   type | thread name |
------------------------------------------------------------------------------
| datasource1-1 |   idle |          10000 |         3 | pooled |             |
------------------------------------------------------------------------------
| datasource1-2 | active |           1300 |         2 | pooled |     http-w1 |
------------------------------------------------------------------------------
==============================================================================

위 테이블에서처럼 상태가 active인 경우에 thread name 정보가 나오게 된다. datasource1-2 커넥션은 릭(leak)일 수도 있으므로 http-w1 쓰레드는 가장 최근에 커넥션을 사용한 쓰레드가 된다.

또한 -id 옵션을 통해 하나의 커넥션에 대한 정보를 볼 수 있다.

johan>dsconinfo -con johan_container1 -id datasource1-1 datasource1
===============================================
Connection[datasource1-1] information in the engine container[johan_container1]
-----------------------------------------------
| state | state-time(ms) | use-count |   type |
-----------------------------------------------
|  idle |        506.617 |         0 | pooled |
-----------------------------------------------
===============================================

-id 옵션에 쓰이는 인자는 dsconinfo 명령어를 통해 나타난 커넥션 리스트에서 나타난 id이다. 예를 들어, datasource1-1 커넥션 id를 인자로 줬을 때 state, use count, type 정보를 볼 수 있다. 만약 데이터 소스에 getConnection Trace 기능을 사용한다면 이 커넥션을 가져간 어플리케이션들의 정보를 getConnection 할 때의 스택 덤프로 확인할 수 있다. 그리고 SQL Trace를 사용한다면 해당 커넥션에서 실행중인 SQL이 무엇인지 확인할 수 있다. 그리고 이때도 -t 옵션이 적용된다.

 

커넥션 공유(connection sharing)은 같은 트랜잭션 내에서는 하나의 리소스에 대해 항상 하나의 커넥션만 사용하는 것을 보장한다는 개념으로, JCA 스펙에 언급되어 있다. JDBC 커넥션 풀 입장에서의 리소스는 대부분 데이터베이스(또는 데이터 소스)이다. JEUS의 JDBC 커넥션 풀에서는 특별한 설정이 필요없이 기본적으로 XA 데이터 소스에 대해 커넥션 공유를 제공하며 로컬 XA 데이터 소스도 마찬가지로 제공한다. ProFrame과 같은 어플리케이션 프레임워크에서는 같은 트랜잭션 내에서 하나의 데이터 소스에 여러 번 getConnectionclose를 반복하게 되는 경우가 많으므로 커넥션 공유를 사용하는 것이 바람직하다. 그렇지 않으면 하나의 DB에 대해 여러 개의 물리적 커넥션이 트랜잭션에 참여하기 때문에 DB 입장에서는 불필요하게 많은 트랜잭션 락을 필요로 하게 되고 트랜잭션 성능에 영향을 미칠 수 있다.

만약 커넥션 공유를 사용하고 싶지 않을 때는 XA 데이터 소스를 사용하는 Java EE 컴포넌트 설정(web.xml, ejb-jar.xml 등)에 아래와 같이 설정할 수 있다. 참고로<res-ref-name>에는 보통 JEUSMain.xml에 설정된 데이터 소스의 JNDI 이름을 적어주면 된다.

<resource-ref>
    <res-ref-name>jdbc/xads</res-ref-name>
    <res-type>javax.sql.DataSource</res-type>
    <res-sharing-scope>Unshareable</res-sharing-scope>
</resource-ref>

참고로 아무 설정을 하지 않으면 기본적으로 <res-sharing-scope>가 Shareable 이기 때문에 Servlet이나 EJB 컴포넌트에서 항상 커넥션 공유를 사용하게 되는 것이다.

단, 로컬 XA 데이터 소스는 항상 커넥션 공유를 해야 하기 때문에 Unshareable로 설정하면 에러(java.sql.SQLException)를 발생하도록 되어 있다.

 

728x90

'PROGRAMMING > Database' 카테고리의 다른 글

테이블 명세서 추출 쿼리  (0) 2017.10.03
MSSQL 실행계획이 없다는 에러  (0) 2017.10.03
charindex를 이용한 revers 추출 예제  (0) 2015.06.05
행을 열로 바꿔주는 쿼리  (0) 2015.06.03
idendity on / off 하기  (0) 2015.05.10

댓글