개발관련/삽질

Apache Commons-DBCP / Hikari-DBCP 정리

동팡 2021. 4. 5. 17:58

(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

12bme.tistory.com/313

www.tutorialspoint.com/what-are-bind-variables-how-to-execute-a-query-with-bind-variables-using-jdbc

aboutdb.tistory.com/232

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