Apache Commons-DBCP / Hikari-DBCP 정리
(4.5 부터 작성중~~~~...)
우리가 자주 사용하는 DBCP를 분석한다.
Apache Commons-DBCP
defaultAutoCommit | driver default 오토커밋 여부를 결정한다. |
defaultTransactionIsolation | driver default READ UNCOMMITTED READ_COMMITED REPETABLE_READ SERIALIZABLE 보통 DBMS의 경우, READ_COMMITED ~ REPETABLE_READ |
cacheState | 모르겠음 |
defaultQueryTimeout | default null 쿼리문의 타임아웃을 설정한다. 그러나, DBMS의 쿼리 타임아웃 설정을 우선시한다. |
enableAutoCommitOnReturn | 모르겠음 |
initialSize | default 0 커넥션 풀을 최초 초기화할 때 생기는 커넥션의 개수 |
maxTotal | default 8 마이너스 값의 경우 무제한 커넥션 풀의 최대 생성 가능 커넥션 개수 |
maxIdle | default 8 마이너스 값의 경우 무제한 커넥션 풀에 반납할 때 최대한 남을 수 있는 커넥션 개수 |
minIdle | default 0 최소한 남을 수 있는 커넥션 개수 |
maxWaitMillis | default 무제한 커넥션 풀에서 커넥션을 얻기 위해 기다리는 시간이다. Tomcat의 경우, Tomcat 서버 쓰레드가 무한정 대기하는 불상사가 생길 수 있다. |
validationQuery | default - 커넥션의 헬스 체크할 때 어떤 쿼리를 써야하는지 결정한다. 1row만 반환하는 SELECT 쿼리만 써야한다. |
validationQueryTimeout | default 무제한 validation 쿼리의 타임아웃을 지정한다. |
testOnCreate | default false 커넥션의 생성과 동시에 유효성 검사를 실시한다. |
testOnBorrow | default true 커넥션 풀에서 커넥션을 갖고 올 때마다 유효성 검사를 실시한다. 만약 유효성 검사를 실패하면 해당 커넥션을 폐기하여 다른 커넥션을 요청한다. |
testOnReturn | default false 커넥션을 반납하기 전에 유효성 검사를 실시한다. |
testWhileIdle | default false Evictor에 의해 주기적으로 커넥션 검사를 실시한다. 커넥션이 유효하지 않을 경우, 폐기한다. |
timeBetweenEvictionRunsMillis | default -1 Evictor의 가동 주기를 설정한다(ms 단위). 음수 값을 경우, 실행하지 않는다. |
numTestsPerEvictionRun | default 3 Evictor를 가동할 때 유효성 검사를 할 커넥션의 개수 |
minEvictableIdleTimeMillis | default 30분 Evictor를 사용하여 커넥션 유휴시간을 확인해 설정 값 이상일 경우 커넥션을 제거한다. |
softMinEvictableIdleTimeMillis | default -1 모르겠음 |
maxConnLifetimeMillis | default -1 커넥션의 최대 유지 시간이다. 해당 값이 넘을 경우, 사용 또는 유효성 검사 때 폐기된다. 음수 값은 무한을 의미한다. |
logExpiredConnections | default true maxConnLifetimeMillis 설정에 의해 커넥션이 폐기될 경우 로깅을 한다. |
connectionInitSqls | default null 모르겠음 |
lifo | default true LIFO, 최근에 사용한 커넥션(Last-In)을 반환받는다(First-Out). false를 설정할 경우, FIFO 형태로 커넥션을 반환한다. |
removeAbandoned | default false 활성화된 커넥션이 Fetch 시간이 removeAbandonedTimeout 값을 넘어서면 커넥션 강제 Close의 대상이된다. 대량 SQL의 경우, 해다 옵션에 의해 커넥션이 소멸될 수 있다. 해당 값의 설정보다 SqlStatement Timeout을 통해 제어하는게 더 좋지 않을까 생각이든다. |
poolPreparedStatements | defualt false 현재 커넥션에서의 PreparedStatement의 풀링을 실시한다. |
maxOpenPreparedStatements | default 제한 없음 풀링하고자하는 preparedStatement의 개수를 지정한다. 만약 5를 설정할 경우, 10개의 커넥션이 풀에 존재하면 50개의 PreparedStatement가 캐시에 저장된다. 크기에 유의하며, 반복적인 Select가 잦은 서비스에 poolPreparedStatements/maxOpenPreparedStatements 옵션을 설정한다. |
번외) PreparedStatement
PreparedStatements Pool 관련 PreparedStatement를 통해 바인드 변수를 사용할 수 있다. 바인드변수를 통해 DBMS 라이브러리 캐시(shared-pool)의 공유할 수 있는 커서를 생성한다. 이렇게 생성한 커서들을 통해 SQL 실행계획을 공유할 수 있다. SQL 실행계획을 공유할 경우의 이점은 SQL 파싱을 하드 파싱이 아닌 소프트 파싱으로 진행할 수 있다. 소프트 파싱을 할 경우, 하드 파싱(SQL 최적화 과정)을 피할 수 있다. 하드 파싱(SQL 최적화 과정)은 다음의 사항들이 존재한다. - 후보 실행계획 생성 및 각각의 비용 계산, SQL 엔진이 실행할 수 있도록 코드 생성 위와 같이 PreparedStatement 사용을 통해 DBMS에서 SQL 소프트 파싱을 진행할 수 있다. |
(내 기준) Common-DBCP Best Practice
DBCP의 경우, 비지니스 서버에 따라 설정이 매우 상이하다.
defaultAutoCommit = true defaultQueryTimeout = 10 lifo = true(default: true) maxTotal = 300 initialSize = 40 minIdle = 40 maxIdle = 60 maxWait = 5000 testOnBorrow = false testWhileIdle = true numTestsPerEvictionRun = 7 TimeBetweenEvictionRunsMilli=300000 minEvictableIdleTimeMillis = -1 poolPreparedStatements = true maxOpenPreparedStatements = 5 validationQuery = select 1 (PostgreSQL 기준) validationQueryTimeout = 10000 |
[조건] - 리눅스 서버의 TCP/IP 소켓의 지속시간은 30분 - DBMS의 커넥션 타임아웃은 30분 - DBMS의 쿼리 타임아웃은 10초이다. - DBMS는 커넥션을 300개 이상 맺을 수 있다. - DBMS는 라이브러리 캐시(Shared-Pool)에 커서를 2000개 이상을 담을 수 있다(크기로 파악 못해 ㅈㅅ). - OLTP 환경 [설명] - (가정) : 현재 OLTP 환경에서 10초 이상 되는 쿼리는 없고 간략한 쿼리를 진행한다. 그렇기 때문에 Timeout이 발생하면 문제가 생기는 것이다. - 많은 과부하를 예상 할 수 있기 때문에 최소한의 커넥션은 40개를 들 고 있는다(상황에 맞게 변경 필요). - 어차피 40개 들고 있어야하기 때문에 최초 생성할 때 40개를 생성한다. - testOnBorrow의 기능은 비활성화 하였다. : testOn* 옵션은 커넥션 풀에 많은 부하를 줄 수도 안 줄 수도 있다. : 매번 커넥션을 획득할 때 유효성 검증은 할 필요 없다. 성능에 해를 끼칠 수 있다. - 주기적으로 Idle 커넥션의 유효성 검증을 실시한다. : DBMS의 커넥션 타임아웃에 의해 TimeBetweenEvictionRunsMilli 값이 변경될 수 있다. : 5분 마다 7개의 Idle 커넥션에 대해 유효성 검증을 실시한다. : 30분이 될 때 42개(6 * 7 = 42)의 Idle 커넥션의 유효성 검증을 실시한다. : 잦은 유효성 검증은 성능에 해를 끼칠 수 있다. - 유효성 검증을 위한 쿼리와 시간은 임의로 해도 괜찮을 것 같다. - PrepareStatement Pooling은 아직 분석이 되지 않았지만 커서를 적극적으로 활용하기 위해서는 필요한 옵션이라 생각한다. - PrepareStatement Pooling 개수는 각 커넥션 당 5개까지의 쿼리문을 캐싱할 수 있다( maxActive(300) * 5 = 1500). ※ maxActive, maxIdle의 값을 똑같이 할 수 있다. 그러면 커넥션을 소멸과 생성 없이 영속적으로 사용할 수 있다. ※ 사용하는 JDBC가 Connection.isValid()를 구현하였으면 validationQuery를 생략하는 것이 이득이 될 수 있다. ※ PrepareStatement Pooling: 보통의 DBMS는 라이브러리 캐시(Shared-Pool)에서 SQL 실행 계획을 캐싱한다... 근데 DBCP에서의 PrepareStatement Pooling을 통해 또 캐시를한다?? 좀 뭔가 이상하다.. 추가 분석이 필요하다. (생각이 다를 경우, 꼭 말씀해주세요!! 서로 배울 수 있는 기회를 주세요!) |
Hikari-DBCP
... | ... |
아래 사항 정리해야함 21. 5. 12 - ehdvudee
HikariDBCP는 test-while-idle이 존재하지 않는다. 그러면 Idle 커넥션에 대해 유효성 검증을 어떻게 하는 것인가?
일단 결론적으로 Idle 커넥션을 계속 유지하는, 소켓을 계속 유지하는 Commons-DBCP와는 다른 철학을 갖고있다.
HikariDBCP는 Idle 커넥션 갱신 방식을 지양한다.
test-while-idle을 지속적으로 할 경우, 네트워크 인프라 설정과 DB의 WAIT_TIMEOUT을 존중하지 않으며, DB에 불필요한 SQL 요청을 한다는 입장이다.
test-while-idle을 통해 test-on-borrow를 개선 못한다는데... 이부분은 필자는 다르게 생각한다(필자가 잘못 이해했을 수도 있다.).
즉, HikcariDBCP의 입장을 정리하면 다음과 같다github.com/brettwooldridge/HikariCP/issues/766).
- test-while-idle은 네트워크 인프라, DB의 설정을 존중하지 않고 Idle 커넥션 유지한다.
- test-while-idle 또는 test-on-borrow를 통해 지속적인 유효성 검증은 불필요한 부하를 야기한다(네트워크, 방화벽, DB 등).
- 때문에, HikariDBCP는 maxLifeTime까지만 사용한 후, 커넥션을 폐기한다.
- 폐기된 커넥션의 교체는 두자리의 ms 단위이며, negative attenuation을 통해 한번에 폐기가 발생되지 않는다.
- 즉, maxLifeTime 사용 후 폐기 그리고 생성이 위의 test-while-idle, test-on-borrow 비용이 전체적으로 판단했을 때 더 좋다고 판단하는 것 같다.
autoCommit
default true
오토커밋 여부를 결정한다.
connectionTimeout
default 30000(ms)
커넥션 풀에서 커넥션을 얻기 위해 기다릴 수 있는 최대 시간을 의미한다.
해당 값이 초과되면 SQLException을 던진다.
최소 250 이상의 값부터 지정할 수 있다.
idleTimeout
minimumIdle 개수가 될 때 까지 작동을한다.
minimumIdle값이 maximumPoolsize 값보다 낮아야 작동한다(이하).
해당 시간이 지나면 idle 커넥션 폐기를 진행한다.
maxLifetime
default 1800000(ms, 30분)
커넥션 풀에 유지할 수 있는 최대시간을 의미한다.
HikariDBCP는 강력하게 권고하는 사항은 다음과 같다.
네트워크 또는 DB에 맞게 커넥션(소켓) 타임아웃과 맞춘다.
만약 네트워크 또는 DB에 커넥션 유지 타임 아웃이 30분일 경우, 해당 값은 29분 55~58초 정도 설정한다.
최소 값은 30초이다.
minimumIdle
default maximumPoolSize와 같다
maximumPoolSize
최대 생성 커넥션 개수
pkgonan.github.io/2018/04/HikariCP-test-while-idle
참고 문헌
zzikjh.tistory.com/entry/DBCP-%EC%82%AC%EC%9A%A9%EC%8B%9C-poolPreparedStatements-%EC%86%8D%EC%84%B1%EC%9D%B4-%EC%84%B1%EB%8A%A5%EC%97%90-%EB%AF%B8%EC%B9%98%EB%8A%94-%EC%98%81%ED%96%A5zzikjh.tistory.com/entry/DBCP-%EC%82%AC%EC%9A%A9%EC%8B%9C-poolPreparedStatements-%EC%86%8D%EC%84%B1%EC%9D%B4-%EC%84%B1%EB%8A%A5%EC%97%90-%EB%AF%B8%EC%B9%98%EB%8A%94-%EC%98%81%ED%96%A5
www.tutorialspoint.com/what-are-bind-variables-how-to-execute-a-query-with-bind-variables-using-jdbc
engineering-skcc.github.io/cloud/tomcat/apache/DB-Pool-For-Event/
commons.apache.org/proper/commons-dbcp/configuration.html
d2.naver.com/helloworld/5102792
uncle-bae.blogspot.com/2016/04/common-dbcp.html