[Tomcat] Tomcat JDBC Connection Pool

 

[ 소개 ]

- JDBC_Connection_Pool 은 Apache_Commons_DBCP 를 대체 가능하다. (기본값: Apache_Commons_DBCP_2 사용)

1004lucifer

1. JDBC_Connection_Pool 을 사용해야 하는 이유

 1) Commons_DBCP v1.x 는 단일 스레드를 사용한다. (DBCP_2 해당안됨)

 2) Commons_DBCP 논리적 CPU 수가 증가하고 객체를 빌리거나 반환하려는 동시 스레드 수가 증가함에 따라 성능이 저하된다. (DBCP_2 해당안됨)

 3) Commons_DBCP 는 60개가 넘는 클래스가 있지만 tomcat-jdbc-pool core 는 8개의 클래스 이므로 추후 요구사항에 따른 적은 수정만 필요하다.

 4) Commons_DBCP 는 정적 인터페이스를 사용하기에 올바른 JVM 버전을 사용하지 않으면 NoSuchMethodException 이 발생할수 있다.

 5) Tomcat_JDBC_Pool 은 라이브러리 자체에 추가적인 스레드를 추가하지 않고 비동기적으로 Connection 을 검색하는 기능을 구현하고 있다.

 6) Tomcat_JDBC_Pool 은 Tomcat 모듈이며, Tomcat 에서 사용하는 단순화된 로깅 프레임워크인 Tomcat JULI 에 의존한다.

 7) javax.sql.PooledConnection 인터페이스를 사용하여 기본 연결을 검색한다.

 8) Pool 이 비어있고 스레드가 Connection 대기중인 경우, Connection 이 반환되면 Pool은 대기중인 올바른 스레드를 다시 깨운다.


2. JDBC_Connection_Pool 에 추가된 기능

 1) 높은 동시성 환경과 Multi Core/CPU 시스템을 지원한다.

 2) 인터페이스의 동적 구현은 JDK의 낮은 버전으로 컴파일된 경우에도 런타임 환경을 지원하고 java.sql, javax.sql 인터페이스를 지원한다. (JDBC 드라이버가 동일한 경우)

 3) Validation 간격 - Connection 을 사용할 때마다 Validate 를 할필요 없으며, Connection 을 가져오거나 반환할 때 Validation 을 할 수 있지만, 우리가 구성한것보다 더 많이 Validation 을 수행하지는 않는다.

 4) Run-Once 쿼리는 Database 연결될 때 한반만 실행하도록 구성하는 쿼리다. Connection 이 맺어지는 전체 시간동안 세션에 대한 설정을 하는데 유용하다.

 5) 사용자 지정 인터셉터를 구성하여 성능을 향상시킬 수 있다. 인터셉터를 사용하여 쿼리수집 상태, 세션캐시 상태, Connection 실패에 대한 재연결, 쿼리 재시도, 쿼리캐시결과 등을 수행할 수 있다. 옵션은 무궁무진하며 인터셉터는 java.sql / javax.sql 인터페이스의 JDK 버전에 묶이지 않는다.

 6) 비동기 Connection 검색 - Connection 요청을 대기열에 넣고 Future<Connection> 을 응답받을 수 있다.

 7) idle Connection 처리 개선. Connection 을 직접 Close 하는대신 Connection 을 Pooling 하고 알고리즘을 통해 idle Pool 사이즈를 조정한다.

 8) Pool 의 임계값을 지정하여 Pool 이 꽉차거나 timeout 시에 Connection 이 중단(abandon)된 것으로 간주하는 시점을 결정할 수 있다.

 9) 중단 Connection 타이머는 statement/query 수행 시 재설정 된다. 오랬동안 사용중인 Connection 에 대해서 timeout 발생하지 않도록 허용한다. ResetAbandonedTimer 를 통해 설정 가능하다.

 10) 일정시간 연결이 유지된 Connection 을 닫는다. Pool 에 다시 돌아갈 때 유지 기간에 따라 닫는다.

 11) Connection 이 중단(abandon) 된 것으로 의심되는경우 JMX 알림을 받고 로그를 기록한다. removeAbandonedTimeout 과 유사하지만 아무것도 하지 않고 로그만 쌓는다. suspectTimeout 속성을 통해 설정 가능하다.

 12) Connection 은 java.sql.Driver, javax.sqlDataSource, javax.sql.XADataSource 를 통해서 가져올 수 있으며 dataSourcedataSourceJNDI 속성을 통해 구성한다.

 13) XA Connection 을 지원한다. (하지만 Tomcat 은 JTA를 지원하지 않는다.)



[ 사용 방법 ]

- Tomcat Connection Pool 의 사용법은 최대한 간단히 만들어졌기 때문에 commons-dbcp 에 익숙한 사용자라면 전환이 간단하다. 다른 Connection Pool 에서 전환하는 것도 간단하다.


1. 추가 기능

- Tomcat Connection Pool 은 다른 Pool 이 제공하는 기능에 비해 몇 가지 추가 기능을 제공한다.

 1) initSQL - Connection 이 생성될 때 한번만 수행되는 SQL 을 실행하는 기능

 2) validationInterval - Connection 에 대한 유효성 검사, 너무 자주 실행하지 않도록 유의 필요

 3) jdbcInterceptors - Pool, Query, Result 에 대한 커스텀 처리를 만드는 인터셉터 플러그

 4) fairQueue - Connection 에 대한 FIFO 방식으로 Thread 공정성을 처리하거나 비동기 Connection 을 가져오려면 true 로 설정


2. Apache Tomcat Container 설정

- Tomcat Connection Pool 은 The Tomcat JDBC 문서 에 있는 설명된 리소스로 구성되며, 유일한 차이점은 factory="org.apache.tomcat.jdbc.pool.DataSourceFactory" 속성을 지정해야 한다는 점이다.


3. 다른 독립 Application 설정

- 해당 Connection_Pool 은 tomcat-juli.jar 에만 의존성이 있다.

- org.apache.tomcat.jdbc.pool.DataSource Bean 을 인스턴스화 하여 다른 독립 프로젝트에서 Pool 을 구성할 수 있다.

- (아래 설명되어 있는것과 같이) Connection Pool 을 JNDI 리소스로 구성하는데 사용한것과 동일한 속성이 DataSource 를 Bean 으로 구성하는데 사용된다.


4. JMX

- Connection Pool 객체는 등록할 수 있는 MBean 을 노출한다.

- Connection Pool 객체가 MBean 을 생성하려면 jmxEnabled 설정을 true 로 해야한다. (Pool 이 MBean 서버에 등록된다는 의미가 아니라 MBean 이 생성되는것을 의미)

- Tomcat 과 같은 컨테이너는 Tomcat 스스로 MBean 서버에 DataSource를 등록하는데, 그러면 org.apache.tomcat.jdbc.pool.DataSource 객체가 실제 Connection Pool MBean 에 등록한다.

- 만약 컨테이너가 아닌경우 DataSource 를 지정한 이름으로 직접 등록이 가능하며, 등록한 기본 Pool 이 전파된다.
- 이렇게 하려면 mBeanServer.registerMBean(dataSource.getPool().getJmxPool(), objectname) 과 같이 호출한다. 이 함수를 호출하기전에 dataSource.createPool() 을 호출하여 Pool 이 생성되었는지 확인한다.



[ 속성 ]

- common-dbcp 와 tomcat-jdbc-pool 을 간단히 전환할 수 있도록 대부분의 속성은 동일하고, 동일한 의미를 갖는다.


1. JNDI 팩토리 및 유형

속성 설명
factory 필수값이며, 다음 값을 넣는다. org.apache.tomcat.jdbc.pool.DataSourceFactory
type 값은 항상 javax.sql.DataSource 또는 javax.sql.XADataSource 값 이어야 한다.

유형에 따라 org.apache.tomcat.jdbc.pool.DataSource 또는 org.apache.tomcat.jdbc.poo.XADataSource 가 생성이 된다.


2. 시스템 속성

- JVM의 System Properties 는 JVM 에 생성된 모든 Pool 에 영향을 미친다.

속성 설명
org.apache.tomcat.jdbc.pool.onlyAttemptCurrentClassLoader (boolean)
JDBC Drivers, Interceptors, Validators 와 같은 동적 클래스의 클래스로딩을 제어한다.

기본값인 false 로 설정하면 Pool 은 현재 로더(Pool class를 로드한 클래스로더)를 사용하고, 클래스 로딩에 실패 시 Thread Context Loader 를 사용하여 로드를 시도한다.

true 로 설정하면 Tomcat 8.0.8 이하의 하위호환성을 유지하고 현재 로더만 시도한다.


3. 공통 속성

- 여기 속성들은 commons-dbcp 와 tomcat-jdbc-pool 이 공유하고 있으나 어떤 경우에는 기본값이 다르기도 하다.

속성 설명
defaultAutoCommit (boolean)
Pool 에서 생성된 Connections 의 기본 auto-commit 상태.

설정하지 않으면 JDBC 드라이버 기본값 (setAutoCommit 메소드가 호출되지 않음)
defaultReadOnly (boolean)
Pool 에서 생성된 Connections 의 기본 read-only 상태.

설정하지 않으면 setReadOnly 메소드가 호출되지 않음 (Informix 와 같은 일부 드라이버는 read-only 모드가 지원되지 않음)
defaultTransactionIsolation (String)
Pool 에서 생성된 Connections 의 기본 TransactionIsolation 상태.

다음중 하나 (javadoc 참고)
- NONE
- READ_COMMITTED
- READ_UNCOMMITTED
- REPEATABLE_READ
- SERIALIZABLE

설정하지 않으면 호출되지 않으며 기본 JDBC 드라이버가 사용된다.
defaultCatalog (String)
Pool 에서 생성한 Connections 의 기본 Catalog
driverClassName (String)
사용할 FQCN 형식 자바 클래스 이름.

드라이버는 tomcat-jdbc.jar 와 동일한 클래스 로더에서 엑세스 할 수 있어야 한다.
username (String)
Connection 설정을 위한 JDBC 드라이버에게 전달하는 username

DataSource.getConnection(username, password) 메소드는 메소드에 전달된 자격증명을 사용하지 않고 여기에 구성한 정보를 사용한다.

자세한 내용은 alternateUsernameAllowed 속성을 참고.
password (String)
Connection 설정을 위한 JDBC 드라이버에게 전달하는 password

DataSource.getConnection(username, password) 메소드는 메소드에 전달된 자격증명을 사용하지 않고 여기에 구성한 정보를 사용한다.

자세한 내용은 alternateUsernameAllowed 속성을 참고.
maxActive (int)
Pool 에서 할당 가능한 Active_Connection 의 최대 개수 (기본값 : 100)
maxIdle (int)
Pool 에서 항상 보관해야 하는 최대 Connection 개수.

testWhileIdle 이 활성화 되어있는 경우 Idle_Connection 은 주기적으로 체크되고 minEvictableIdleTimeMillis 보다 오래되면 해제된다.
(testWhileIdle 참고)
minIdle (int)
Pool 에 항상 연결되어야 하는 최소 Connection 개수.

Validation_Query 가 실패하면 Connection_Pool 이 minIdle 값 아래로 줄어들 수 있다.
기본값은 initialSize:10 에 영향을 받는다.
(testWhileIdle 참고)
initialSize (int)
Pool 이 시작할 때 생성할 초기 Connection 개수. (기본값: 10)
maxWait (int)
(사용 가능한 연결이 없는경우) Pool 에서 예외를 발생시키기 전에 Connection 이 반환될 때까지 대기하는 최대 milliseconds 값 (기본: 30000, 30초)
testOnBorrow (boolean)
Pool 에서 Connection 을 빌리기전에 객체의 유효성을 검사할지 여부.

객체의 유효성 검사에 실패하면 Pool 에서 삭제되고 다른 객체를 빌리려고 시도한다.
효율적인 유효성 검사를 하려면 validationInterval 을 참고.
기본값 : false
testOnConnect (boolean)
Connection 이 처음 생성될 때 객체 유효성을 거사할지 여부. (기본값: false)
검사 실패하는경우 SQLException 이 발생한다.
testOnReturn (boolean)
Connection 을 Pool 에 반환하기전에 객체 유효성 검사를 할지 여부. (기본값: false)
testWhileIdle (boolean)
Idle_Connection 객체 제거자가 있는경우 객체의 유효성을 검사할지 여부. (기본값: false)

객체가 유효성 검사에 실패하면 Pool 에서 삭제된다.

Pool clear/test Thread 를 실행하려면 true 로 설정해야 한다.
(timeBetweenEvictionRunsMillis 참고)
validationQuery (String)
Connection 호출자에게 전달하기전에 Pool 에서 유효성 검사를 할 SQL 쿼리. (기본값: null)

이 옵션을 지정하면 해당 쿼리는 데이터를 반환하지 않으며, SQLException 도 발생하지 않는다.

설정하지 않은경우 Connection 은 isValid() 메소드로 유효성 검사를 한다.

Example)
- MySQL : SELECT 1
- Oracle : select 1 from dual
- MS_SQL : SELECT 1
validationQueryTimeout (int)
validationQuery 가 실패하기 전까지의 시간(초)

validationQuery 가 수행하는 곳에서 java.sql.Statement.setQueryTimeout(secods) 를 호출하여 작동한다.

Pool 은 쿼리 제한시간은 두지 않으며, 제한시간을 두는것은 JDBC 드라이버에 달려있다.

0 보다 작거나 같은 값인경우 기능이 비활성화 된다. (기본값 : -1)
validatorClassName (String)
(내부에는 있을 수 있지만) 인자없는 생성자와 함께 org.apache.tomcat.jdbc.pool.Validator 인터페이스를 구현하는 클래스 이름.

이 옵션을 지정하면 Validator 인스턴스가 생성이 되고 Connection 의 유효성을 검사할 때 Validation Query 대신 사용된다.

기본값 : null

예시) com.mycompany.project.SimpleValidator
timeBetweenEvictionRunsMillis (int)
idle Connection 에 대해서 Validation / Cleaner 쓰레드의 수행 사이에 대기하는 밀리초 시간 (기본값: 5000, 5초)

이 값을 1초 미만으로 설정하면 안됨.
이 값은 Connection 의 idle, abandoned, validation 을 검사하는 빈도를 결정한다.

maxAge 값이 0 이 아니고 이 설정값보다 낮은경우 maxAge 값으로 대체된다.
numTestsPerEvictionRun (int)
tomcat-jdbc-pool 에서는 사용하지 않음
minEvictableIdleTimeMillis (int)
객체가 Pool 에서 (idle)유휴 상태로 있을 수 있는 최소 시간 (기본값 : 60000, 60초)
accessToUnderlyingConnectionAllowed (boolean)
사용하지 않는 속성

Pool 안에 있는 Connection 에서 unwarp 호출하여 접근 가능하다.

javax.sql.DataSource 를 참조하거나, 리플렉션을 통해 getConnection 을 호출하거나 javax.sq.PooledConnection 으로 캐스팅한다.

(추가설명: DBCP 에서 래핑하기 이전의 원본 커넥션을 가져오는데 잘못된 연상 수행으로 위험해 질 수 있으니 드라이버 고유의 확장 기능을 직접 사용하는 경우가 아니라면 권장하지 않음)
removeAbandoned (boolean)
(abandoned)중단된 Connection 이 removeAbandonedTimeout 을 초과하는 경우 제거 Flag 를 지정한다. (기본값: false)

true 로 셋팅 시 Connection 이 removeAbandonedTimeout 을 초과한경우 중단된 것으로 간주하고 제거할 수 있고, Application 에서 Close 하지 않은 Connection 을 복구할 수 있다.
(logAbandoned 참고)
removeAbandonedTimeout (int)
(사용중인) abandoned Connection 을 제거할 수 있는 시간(초) 설정 (기본값: 60, 60초)

이 값은 Application 에서 가장 오래 실행되는 쿼리 시간으로 설정해야 한다.
logAbandoned (boolean)
abandoned Connection 의 Application 코드에 대한 Stack Trace Log 를 남기도록 지정 (기본값: false)

abandoned Connection 을 로깅 하려면 가져온 Connection 에 대해서 Stack Trace 를 추가해야 하기 때문에 오버헤드가 추가된다. (성능 낮아짐)
connectionProperties (String)
새로운 Connection 연결을 할 때 JDBC 드라이버로 보내는 연결속성 (기본값: null)

문자열의 형식은 [propertyName=property;]* 형식이어야 한다.

"user", "password" 속성은 명시적으로 전달되기에 여기 포함할 필요 없음.
poolPreparedStatements (boolean)
사용하지 않는 속성
maxOpenPreparedStatements (int)
사용하지 않는 속성


4. Tomcat JDBC 전용 추가 속성

속성 설명
initSQL (String)
Connection 이 처음 생성될 때 실행되는 커스텀 쿼리 (기본값 : null)
jdbcInterceptors (String)
org.apache.tomcat.jdbc.pool.JdbcInterceptor 를 extens 한 클래스 리스트(세미콜론으로 구분)

이러한 인터셉터들은 java.sql.Connection 객체의 작업체인에 인터셉터로 삽입된다. (기본값: null)

[미리 정의된 인터셉터]
- org.apache.tomcat.jdbc.pool.interceptor.ConnectionState : auto commit / read only / catalog / transaction isolation level 을 추적
- org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer : opened statements 와 Connection 이 반환될 때 close 되었는지 추적
- 등등

더 많은 내용은 아래 JDBC 인터셉터 구성 내용 참고
validationInterval (long)
과도한 유효성 검증을 피하고 최대한 이 값의 빈도로 검증을 수행한다. (기본값: 3000, 3초)

(Validation)유효성 검증이 필요한 Connection 이지만 이 간격 이내에 유효성 검사을 받은 적이 있으면 유효성 검사를 재수행 하지 않는다.
jmxEnabled (boolean)
JMX에 Pool 을 등록할지 여부 (기본값: true)
fairQueue (boolean)
true 설정 시 getConnection 호출이 FIFO 방식으로 순차적으로 처리됨 (기본값 : true)

idle Connections 목록에 org.apache.tomcat.jdbc.pool.FairBlockingQueue 구현된것을 사용한다.

비동기 Connection 연결을 가져오려면 이 설정이 필요하다.
이 값을 설정하면 Thread 가 도착하는 순서대로 Connection 을 받는다.
성능테스트 시 lock / lock waiting 구현방식에 따라 큰 차이가 있었다.

fairQueue=true 인경우 실행중인 OS에 따라서 프로세스 기본방식이 결정된다.
(os.name=Linux 속성) 리눅스 시스템인경우 Connection_Pool 클래스가 로드되기 전에  org.apache.tomcat.jdbc.pool.FairBlockingQueue.ignoreOS=true 시스템 프로퍼티를 추가하여 리눅스 전용 동작을 비활성화 하고 FIFO Queue 방식을 사용할 수 있다.
abandonWhenPercentageFull (int)
시간 초과된 abandoned Connection 개수가 이 값의 퍼센트를 초과하지 않는 한 Close 되지 않고 로그에 남지 않는다.

값은 0~100 사이 입력 가능 (기본값: 0)

기본값 0 은 removeAbandonedTimeout 에 도달하는 즉시 Close 가 되는것을 의미한다.
maxAge (long)
Connection 을 다시 생성하기 전에 연결을 유지하는 밀리초 시간. (기본값: 0)

Pool 에서 Connection 을 가져올 때 maxAge < 현재시간 - Connection_연결시간 체크하여 (age)시간이 도달한 경우 ReConnect 한 후 가져온다.
Connection 이 Pool 에 반환될 때 maxAge < 현재시간 - Connection_연결시간 체크하여 (age)시간이 도달한 경우 ReConnection 수행한다.

Connection 이 idle 상태이고 timeBetweenEvictionRunsMillis 가 0 보다 큰경우 주기적으로 maxAge < 현재시간 - Connection_연결시간 체크하여 (age)시간이 도달한 경우 ReConnection 수행한다.

maxAgetimeBetweenEvictionRunsMillis 보다 낮게 설정하면 maxAge 값은 timeBetweenEvictionRunsMillis 값으로 셋팅된다. (idle Connection 의 Validation / Cleaning 이 더 자주 실행된다.)

기본값인 0 인 경우 Connection 이 Open된 상태로 유지되고, Connection 을 Pool 에서 가져올때나 Pool 에 돌려줄때, idle Connections 체크 시 age 시간 체크를 수행하지 않는다.
useEquals (boolean)
ProxyConnection 클래스에서 메소드 이름을 비교할 때 String.equals 를 사용하려면 true 로 셋팅하고, == 를 사용하려면 false 를 셋팅한다. (기본값: true)

인터셉터는 개별적으로 구성되기에 이 값은 인터셉터에 적용되지 않는다.
suspectTimeout (int)
시간 초 값 (기본값: 0)

logAbandoned 가 true 인경우, removeAbandonedTimeout 과 유사하지만 Connection 을 Close 하거나 Abandoned 하는것 대신 단순히 경고 로그만 남긴다.

0 이거나 0보다 작은경우 Connectin 의심 체크를 수행하지 않는다.
abandon 체크가 비활성화 되어있거나 값이 0보다 크고 Connection 이 (abandon) 중단 되지 않은경우 체크를 수행한다.

Connection 이 의심스러운경우 경고 메시지를 로그에 남기고 JMX 알림이 한번 전송된다.
rollbackOnReturn (boolean)
autoCommit==false 이면 Connection 이 Pool 로 반환될 때 rollback 을 호출하여 트랜잭션을 종료할 수 있다. (기본값: false)
commitOnReturn (boolean)
autoCommit==false 이면 Connection 이 Pool 로 반환될 때 commit 을 호출하여 트랜잭션을 완료할 수 있다. (기본값: false)
rollbackOnReturn==true 인 경우 이 속성은 무시된다.
alternateUsernameAllowed (boolean)
기본적으로 성능상의 이유로 jdbc-pool 의 DataSource.getConnection(username, password) 호출을 무시하고, username, password 의 글로벌 속성으로 구성된 이전에 Pool 된 Connection 을 가져온다. (기본값: fasle)

Pool 은 Connection 을 요청할때마다 매번 다른 자격증명을 사용하도록 구성할 수 있다.
true 로 설정 시 간단하게 DataSource.getConnection(username, password) 를 호출하여 해당 메소드의 설명된 기능을 사용할 수 있다.

만약 user1/password1 으로 Connection 자격증명을 요청했는데 이전에 user2/password2 로 Connection 연결된게 있다면 Connection 을 Close 하고 이전에 연결된 Connection 을 다시 Open 하여 가져온다.
이렇게 하면 Pool 사이즈가 스키마 레벨이 아닌 글로벌 레벨로 관리된다.

이 속성은 bug 50025 의 기능 향상을 위해 추가되었다.

설명: DataSource.getConnection(username, password)를 사용하더라도 Tomcat 에 (글로벌 커넥션) JNDI 구성이 되어 있다면 해당 커넥션을 가져오는게 우선이며, 이 옵션을 true 로 설정 시 JNDI 값을 가져오지 않고 새로 연결을 맺는다.
dataSource (javax.sql.DataSource)
Connection Pool 에 데이터소스를 주입하면 Pool 은 java.sql.Driver 인터페이스 대신 설정한 데이터소스를 사용하여 Connection 을 연결한다. (기본값: null)

이 기능은 연결 문자열 대신에 데이터소스를 사용하여 XA Connections 를 Pool 하는데 유용하다.
dataSourceJNDI (String)
JNDI 를 조회하고 DB에 커넥션 연결에 사용할 데이터소스의 JNDI 이름 (기본값: null)
useDisPosableConnectionFacade (boolean)
Connection 연결이 Close 된 후 재사용할 수 없도록 Facade 를 설정하려면 이 값을 true 로 설정 (기본값: true)

이렇게 하면 Thread 가 이미 Close 된 Connection 의 참조를 유지하여 해당 Connection 에 대한 쿼리 수행을 방지한다.
logValidationError (boolean)
(Validation) 유효성 검사 단계 중 발생한 에러를 로그에 기록하려면 true 로 설정한다. (기본값: false)

이전버전의 호환성을 위해 기본값은 false 이다.
propagateInterruptState (boolean)
인터럽트 된 Thead 의 상태를 전파하려면 true 로 설정한다. (인터럽트 상태를 지우지 않으려면..)

이전버전의 호환성을 위해 기본값은 false 이다.
ignoreExceptionOnPreLoad (boolean)
Pool 을 초기화 하는동안 Connection 생성 오류를 무시할지 여부 (기본값: false)

Pool 을 초기화 하는 동안 Connection 생성 오류를 무시하려면 true 로 설정한다.
Exception 을 발생시켜 Pool 의 초기화를 실패하게 하려면 false 를 설정한다.
useStatementFacade (boolean)
Statement Proxy 가 설정된 경우 Close 된 Statement 의 equals()hashCode() 메소드를 활성화 하기 위해 Statement 를 래핑한다. (기본값: true)



[ 고급 사용법 ]

1. JDBC 인터셉터

- 인터셉터 사용방법의 예시를 보려면 org.apache.tomcat.jdbc.pool.interceptor.ConnectionState 를 참조한다. 이 간단한 인터셉터는 transaction isolation level / auto commit / read only state 세가지 속성의 캐시로써 시스템이 불필요한 Database 의 통신을 피할 수 있도록 한다.

- 필요에 따라 더 많은 인터셉터가 Pool 의 코어에 추가될 예정이다.

- 인터셉터는 java.sql.Connection 에만 제한되는게 아니라 모든 메소드의 결과를 래핑하는데에도 사용할 수 있다. 쿼리가 예상시간보다 오래 걸릴 때 JMX 알림을 제공하는 쿼리 분석기를 구축할수도 있다.


2. JDBC 인터셉터 구성

- JDBC 인터셉터는 jdbcInterceptors 속성을 사용하여 구성한다. 이 속성은 세미콜론(;) 으로 구분된 클래스 리스트로 구성된다. 클래스 이름이 (fully qualified)정규화 되지 않은경우 org.apache.tomcat.jdbc.pool.interceptor 가 접두사로 붙는다.

- 예제: jdbcInterceptors="org.apache.tomcat.jdbc.pool.interceptor.ConnectionState; org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer"

- 인터셉터도 속성을 가질 수 있다. 인터셉터의 속성은 클래스 이름 뒤에 괄호 안에 지정된다. 여러 속성은 쉼표로 구분된다.

- 예제: jdbcInterceptors="ConnectionState;StatementFinalizer(useEquals=true)"

- Class Names / Property Names / Values 의 주변의 공백 문자는 무시된다.


3. org.apache.tomcat.jdbc.poolJdbcInterCeptor

- 모든 인터셉터에 대한 기본 추상클래스 이며 인스턴스화 할 수 없다.

속성 설명
useEquals (boolean)
ProxyConnection 클래스에서 메소드 이름을 비교 시 String.equals 를 사용하려면 true 로 설정, == 로 사용하려면 false 셋팅 (기본값: true)


4. org.apache.Tomcat.jdbc.pool.interceptor.ConnectionState

autoCommit / readOnly / transactionIsolation / catalog 속성에 대한 Connection 을 캐시한다. 이미 설정된 값으로 getter / setters 를 호출 할때 Database 의 통신을 피하기 위한 성능향샹 기능.

* 속성 없음


5. org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer

- createStatement / prepareStatement / prepareCall 을 사용하여 생성된 모든 Statements 를 추적하고, Connection 이 Pool 로 반환되면 Statements 를 Close 한다.

속성 설명
trace (boolean as String)
Close 되지 않은 Statement 를 추적에 대한 여부, true 설정 시 Connection 이 Close 되고, Statement 가 Close 되지 않았을 때 Stack Trace 로그를 남긴다. (기본값: false)


6. org.apache.tomcat.jdbc.pool.interceptor.StatementCache

- Connection 의 PreparedStatement / CallableStatement 인스턴스를 캐시한다.

- Connection 별로 Statement 가 캐시 된다. 카운트 제한은 같은 Pool 에 있는 모든 Connection 에 대해서 (Global)전역 카운트를 한다. 카운트가 max 에 도달하면 다음 Statement 는 캐시에 반환되지 않고 즉시 Close 된다.

속성 설명
prepared (boolean as String)
true 설정 시 기존에 생성하여 호출에 사용한 PreparedStatement 인스턴스를 캐싱한다. (기본값: true)
callable (boolean as String)
true 설정 시 기존에 생성하여 prepareCall 호출에 사용한 CallableStatement 인스턴스를 캐싱한다. (기본값: true)
max (int as String)
Connection Pool 에 캐시된 Statement 캐시의 개수 제한 (기본값: 50)


7. org.apache.tomcat.jdbc.pool.interceptor.StatementDecoratorInterceptor

- 버그리포트 48392 참고

- Statement 와 ResultSet 을 래핑하여 ResultSet.getStatement().getConnection()Statement.getConnection() 메소드를 사용하는 실제 커넥션에 대한 접근을 제한한다.

* 속성 없음

- 버그리포트 추가설명: Statement 와 ResultSet 에서 Proxy Connection 을 리턴하지 못하는 이슈가 있었고, JdbcInterceptor 에 Proxy Statement/ResultSet 을 구현했다. Proxy 된 Connection 을 사용하는 경우 해당 인터셉터를 추가하여 Proxy 되지 않은 Connection 에 대한 접근을 차단할 수 있다.


8. org.apache.tomcat.jdbc.pool.interceptor.QueryTimeoutInterceptor

- 새로운 Statement 가 생성되면 자동으로 java.sql.Statement.setQueryTimeout(seconds) 가 호출된다. Pool 자체는 쿼리의 Timeout 에 관여하지 않고 JDBC 드라이버가 Timeout 에 관여한다.

속성 설명
queryTimeout (int as String)
쿼리 타임아웃에 설정할 (초)시간, 0 이거나 0 보다 작으면 비활성화 된다. (기본값: 1 초)


9. org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReport

- 쿼리가 (threshod)임계값을 초과하면 WARN 레벨의 로그를 생성한다.

속성 설명
threshold (int as String)
Log 생성하기 전에 최대한 기다릴 수 있는 (밀리초)시간. (기본값: 1000 밀리초)
maxQueries (int as String)
메모리 용량을 다 사용하지 않도록 쿼리 추적하는 최대 개수. (기본값: 1000)
0 이거나 0 보다 적은경우 기능 비활성화
logSlow (boolean as String)
true 설정 시 Slow 쿼리를 로그에 기록 (기본값: true)
logFailed (boolean as String)
true 설정 시 실패한 쿼리를 로그에 기록 (기본값: false)


10. org.apache.tomcat.jdbc.pool.interceptor.SlowQueryReportJmx

- SlowQueryReport 를 확장하고 로그 저장 이외에 모니터링 툴이 반응할 수 있도록 JMX 에 알림을 보낸다. (SlowQueryReport) 부모 클래스로부터 모든 속성을 상속한다.

- 이 클래스는 Tomcat JMX 엔진을 사용하므로 Tomcat 컨테이너가 아닌 외부 Application 에서는 동작하지 않는다. 기본적으로 JMX 알림은 환성화된 ConnectionPool MBean 으로 전송한다.

- SlowQueryReportJmxnotifiPool=false 설정이 되어있는 경우 등록이 가능하다.

속성 설명
notifyPool (boolean as String)
JMX 알림을 SlowQueryReportJmx MBean 으로 보내려면 false 로 설정한다. (기본값: true)
objectName (String)
MBean 서버에 등록하는데 사용할 유효한 javax.management.ObjectName 객체 문자열을 정의한다. (기본값: null)
객체는 tomcat.jdbc:type=org.apache.tomcat.jdbc.pool.inerceptor.SlowQueryReportJmx,name=the-name-of-the-pool 을 사용하여 등록된다.


11. org.apache.tomcat.jdbc.pool.interceptor.ResetAbandonedTimer

- abandoned 타이머는 Connection 이 Pool 에서 체크아웃 될때 시작된다. 즉 Timeout 이 30초인경우 10초 수행 쿼리를 10번 수행 시 abandonWhenPercentageFull 속성에 따라 회수가 가능해지고 abandoned 가 마킹된다.

- 이 인터셉터를 사용하면 Connection 에서 작업을 수행하거나 쿼리가 성공적으로 수행될 때마다 체크아웃 타이머가 리셋된다.

* 속성 없음


[ 코드 예제 ]

- Tomcat JDBC 사용을 위한 다른 구성 예제는 해당 Tomcat 문서에서 확인할 수 있다.


1. 기본 자바

- 데이터 소스를 만들고 사용하는 간단한 예제


2. 리소스

- JNDI 조회를 위한 리소스 설정에 대한 예제


3. 비동기 Connection 검색

- Tomcat JDBC Connection Pool 은 Pool 라이브러리에 스레드를 추가하지 않고도 비동기 Connection 검색을 지원한다.

- 이 작업은 Future<Connection getConnectionAsync() 메소드를 데이터소스에 추가하여 호출한다.

- 비동기 검색을 사용하려면 아래 두가지 조건을 충족해야 한다.
 1) fairQueue 속성을 true 로 설정
 2) 데이터소스를 org.apache.tomcat.jdbc.pool.DataSource 로 캐스팅 해야한다.

- 비동기 기능을 사용하는 예제


4. 인터셉터

- 인터셉터는 특정 Connection 이나 하위 구성요소에서 기능을 활성화 / 비활성화 / 수정 할 수 있는 강력한 방법이다.

- 인터셉터가 유용한 경우의 사례는 다양하다. 기본적으로 성능상의 이유로 Connection Pool 은 (stateless)상태가 없다.

- Pool 의 상태는 속성을 일부러 설정한경우 defaultAutoCommit, defaultReadOnly, defaultTransactionIsolation, defaultCatalog 상태를 설정할 수 있으며, 이 속성은 Connection 이 생성될 때만 설정되고 사용중에 속성을 수정해도 재설정 되지 않는다.


- 인터셉터는 인자가 없는 생성자를 가진 org.apache.tomcat.jdbc.pool.JdbcInterceptor 를 extends 한 클래스다.


- Pool 에서 Connection 을 가져오면 인터셉터는 아래 메소드를 구현하여 초기화 하거나 다른 방식으로 이벤트에 반응할 수 있다. 이 메소드는 Connection Pool 자신의 ConnectionPool parent 와 기본 Connection 인 PooldConnection con. 두개의 파라미터를 가지고 있다.


- java.sql.Connection 객체가 invoke 되면 아래 메소드가 같이 invoke 된다. Method method 는 실제 invoke 된 메소드 이고, Object[] args 는 넘겨받은 인자이다.


- 아래와 같이 Connection 이 이미 Close 된 경우에는 java.sql.Connection.close() 함수가 정상 적으로 수행되지 않는 간단한 예를 보여줄 수 있다.


- 메소드 이름도 같이 비교하는데 "close".equals(method.getName()) 을 수행할수도 있지만 위에서는 메소드 이름과 static final String 을 직접 비교를 했다. JVM 스펙에 따르면 메소드 이름과 static final String 은 정적 상수 Pool 에 있으므로 reference 비교도 가능해야 한다. 물론 아래와 같이 할수도 있다. compare(String, Method) 는 인터셉터에서 useEquals 플래그를 사용하며, useEquals=true 를 설정 시 reference 비교나 String 값 비교를 한다.


- Pool 시작 / 중지
Connection Pool 이 Start 되거나 Close 될 때 알림을 받을 수 있다. 인스턴스 메소드 이더라도 인터셉터 클래스당 한번만 알림을 받게되며, Pool 에 연결되지 않은 인터셉터를 사용하여 알림을 받게된다. JdbcInterceptor 확장 클래스에서 이러한 메소드를 오버라이드 할 때 super 를 호출하는 것을 잊으면 안된다.


- 인터셉터 설정
인터셉터는 jdbcInterceptors 속성 또는 setJdbcInterCeptors 메소드를 사용하여 구성한다. 인터셉터에는 속성이 있을 수 있으며 아래와 같이 구성할 수 있다.


- 인터셉터 속성

인터셉터에는 프로퍼티가 있을 수 있으므로 인터셉터 내에서 이러한 프로퍼티 값을 읽을 수 있어야 한다. 예를들어 아래와 같이 setProperties 메소드를 오버라이드 할 수 있다.


5. 실제 JDBC Connection 가져오기

- Connection Pool 은 적절한 Pooling 을 위해 실제 Connection 을 래핑한다. 또한 이러한 래퍼에 특정 기능을 수행할 수 있도록 인터셉터를 생성한다.

- 실제 Connection 이 필요한 경우에 java.sql.PooledConnection 인터페이스를 사용하여 가져올 수 있다.




참고
 - https://tomcat.apache.org/tomcat-11.0-doc/jdbc-pool.html


댓글