[Common DBCP] 설정 및 예

[Common DBCP] 설정 및 예

DBCP 문제 해결기 

1. 문제상황 : 
- 오픈하고 지금까지 커넥션 문제가 없었으나, 요청이 현재 3배 이상 증가하여 커넥션 문제가 발생하고 있었음. 
- 발생문제 : Cannot get a connection, pool error Timeout waiting for idle object 관련 예외가 계속해서 발생함. 
- DBA로 부터 너무많은 커넥션 요청이 들어온다는 보고를 받음 

2. 분석 : 
- 커넥션을 대기하는 시간동안 커넥션을 획득하지 못해서 발생한 오류 
- 즉, maxWaitMillis를 넘어서도 커넥션을 획득하지 못하는 문제가 발생. 

3. 커넥션 설정 확인 : 
BEFORE : 
maxWait=600
slowQueryTime=300
initialSize=5
maxActive=30
maxIdle=20
minIdle=5
useStatementCache=true
statementCacheSize=250
testOnBorrow=false
testOnReturn=false
testWhileIdle=false
timeBetweenEvictionRunsMillis=600000
minEvictableIdleTimeMillis=3600000
queryTimeout=0
useSqlLogForamt=false
connectionProperties=oracle.net.CONNECT_TIMEOUT=5000;oracle.jdbc.ReadTimeout=60000
# beta
beta.queryTimeout=7
beta.useSqlLogForamt=false


--> 상기 설정은 하나의 커넥션이 1시간동안 idle로 되어 잇으면 커넥션이 notValid한 것으로 판단하는 것이다. 
--> 초기 maxActive는 30으로 설정되었고, maxIdle값은 20으로 설정되었다. 

#즉 상기 설정을 통해서 커넥션이 20개 이상이 되는경우 커넥션을 맺고, 사용후에 바로 close한다. 그리고 요청이 필요한경우 다시 connection을 맺기 위해서 DB접근을 계속하는 상황이 된다. 

#또한 실제 Idle한 커넥션은 1시간이 지나면 evict 되어 재 접속이 필요한 상황이 된다. 

AFTER : 수정이후 

maxWait=600
slowQueryTime=300

initialSize=5
maxActive=30
maxIdle=30
minIdle=5
useStatementCache=true
statementCacheSize=250
testOnBorrow=false
testOnReturn=false
testWhileIdle=true
validationQuery=SELECT 1 FROM DUAL
timeBetweenEvictionRunsMillis=150000
minEvictableIdleTimeMillis=-1
numTestsPerEvictionRun=5
queryTimeout=0
useSqlLogForamt=false
connectionProperties=oracle.net.CONNECT_TIMEOUT=5000;oracle.jdbc.ReadTimeout=60000
# beta
beta.queryTimeout=7
beta.useSqlLogForamt=false
- maxActive와 maxIdle값을 같게 설정하였다. 즉, 커넥션제한을 미리 설정해두고, 사용후 반납하는 일이 없도록 설정하였다. 
- 상기 설정은 idle상태의 커넥션을 대상으로 validationQuery를 보내게 설정하였다. 
- 또한 커넥션 검사시간을 150000으로 설정하였다. 매 150000마다 커넥션 검사를 시작한다. 
- minEvictableIdleTimeMillis=-1로 설정하여 풀에 있는 커넥션은 무조건 살아 있다고 가정한다.
- numTestsPerEviceionRun=5로 설정하여 한번  커넥션 valid 할때바다 5개를 검사하도록 지정하였다. 

4. 결과 
- 커넥션을 기다리다가 타임아웃 되는 현상이 사라졌다.
- 매 순간마다 커넥션을 계속 맺는 현상이 사라졌다. 

--------------------------------------------------------------------------------------------------------

Apache Common DBCP

--------------------------------------------------------------------------------------------------------

Common DBCP란 :
Common DBCP는 Apache Common의 프로젝트 하위에 있는 데이터베이스 커넥션 풀을 제공하기 위한 기능을 제공한다.

DB 트랜잭션을 처리하기 위해서 가장 비용이 많이 드는 것은 데이터베이스와 커넥션을 신규로 생성하는 과정으로 DBCP를 이용하면 생성된 커넥션을 pool에 넣고 재사용하여 성능을 극대화 하는 방법을 제공한다.

DBCP2의 특징 : 
common-dbcp2 는 common-pool2 패키지 내에 포함되어 있으며, Java 7 이상에서 동작한다. (JDBC 4.1)

DBCP2는 Commons Pool2를 기반으로 한다. 
기존 DBCP보다 성능이 더 좋아졌다. 
JMX을 지원하여 DBCP 1.x버젼에 비해서 더 많은 기능을 제공한다. 


DBCP Configuration : 

1. 기본 설정 : 
1.1 username : 커넥션을 생성하기 위한 DB사용자 이름
1.2 password : 커넥션을 생성하기 위한 DB사용자 비밀번호
1.3 url      : 커넥션을 생성하기 위한 DB URL
1.4 driverClassName : 사용될 JDBC의 풀 자바 클래스 이름 
1.5 connectionProperties : 새로운 커넥션 생성을 위해서 JDBC 드라이버에 전달할 속성들을 의미한다. 
   [propertyName=property;]* 의 형식을 가진다. 

2. 트랜잭션 관련 설정 : 
2.1 defaultAutoCommit 
- 기본값 : driver default
- 설명 : 풀에 생성된 커넥션의 auto-commit상태를 설정한다. 설정을 하지 않으면 setAutoCommit메소드가 호출되지 않는다. 

2.2 defaultReadOnly 
- 기본값 : driver default
- 설명 : 풀에 의해서 생성된 커넥션의 read-only상태를 설정한다. 설정을 하지 않으면 setReadOnly메소드가 호출되지 않는다. (Infomix와 같은 몇몇 드라이버는 이 설정을 지원하지 않는다.)

2.3 defaultTransactionIsolation
- 기본값 : driver default
- 설명 : 기본 트랜잭션 Isolation을 지정한다. 
NONE
READ_COMMITTED
READ_UNCOMMITTED
REPEATABLE_READ
SERIALIZABLE

2.4 defaultCatalog
- 기본값 : 없음
- 설명 : 풀에 생성된 커넥션의 기본 카탈로그를 설정한다. 

2.5 cacheState 
- 기본값 : true
- 설명 : true로 설정하면 풀된 커넥션은 첫번째 읽기와 쓰기를 수행할때 설정된 readOnly와 autoCommit 값을 캐시해두고 이하 쓰기시에 이를 적용한다. 만약 커넥션이 직접 접근 되어야 하거나 readOnly나 autoCommit 설정이 캐시에서 변경이 되더라도 현재 커넥션에는 반영되지 않는다. 캐싱을 하지 않고자 하는 케이스에서는 이 값을 false로 두면 된다. 

2.6 defaultQueryTimeout 
- 기본값 : null
- 설명 : 이값이 null이 아닌경우 여기에 설정된 정수형의 값은 풀에 의해서 관리되는 커넥션으로 부터 생성된 스테이트 먼트에 사용될 쿼리 타임아웃을 지정하게 된다. null의 의미는 driver의 기본값을 사용하겠다는 의미이다. 

2.7. enableAutocommitOnReturn
- 기본값 : null
- 설명 : true로 설정하면 풀이 커넥션으로 반환될때 Connection.setAutoCommit(true)인지 체크되고, 해당값으로 설정된다. 만약 auto commit가 false인경우라면 true로 변경 설정된다. 

2.8 rollbackOnReturn
- 기본값 : true
- 설명 : true의 의미는 풀로 커넥션이 반환될때 롤백이 수행된다. 단 auto commit이 false이고, 커넥션이 read only모드가 아니어야한다. 


3. 커넥션 개수 설정 
3.1 initialSize 
- 기본값 : 0
- 설명 : 풀이 시작될때 초기에 설정될 커넥션의 개수를 지정한다. 1.2버젼부터 지원

3.2 maxTotal 
- 기본값 : 8
- 설명 : active connection의 최대 개수를 지정한다. 이것은 동시에 풀에 할당될 수 있는 최대 커넥션의 개수이다. 음수로 설정하면 제한이 없다는 의미가 된다. 

3.3 maxIdle
- 기본값 : 8
- 설명 : 풀에서 idle로 남아 잇을 수 있는 최대 개수이다. 이 값보다 넘는 커넥션은 릴리즈 된다. 음수는 제한이 없다는 의미이다. 

3.4 minIdle
- 기본값 : 0
- 설명 : 풀에 idle로 남아있는 최소 개수이다. 즉 풀에 남아 있을 수 있는 최소 커넥션 개수이다. 

3.5 maxWaitMillis
- 기본값 : idenfinitely
- 설명 : 최대 밀리세컨을 지정하는 것으로 커넥션을 얻기 위해 기다리는 시간이다. 커넥션이 모두 다 쓰고 있는 상태에서 스레드가 하나의 커넥션을 얻기 위해 대기하는 시간이다. -1로 설정하면 무한정 기다린다. 

NOTE : 
- 만약 매우 무거운 시스템에서 maxIdle값을 너무 작게 설정하면, 커넥션을 닫고나서 바로 즉시 커넥션을 연결하는 일이 발생할 수 있다. 이 결과는 커넥션을 순간만 이용하고 커넥션을 여는 시간보다 닫는시간이 짧게 되는 현상이 나타난다. 이것은 idle 커넥션의 개수가 maxIdle까지 증가하는 현상을 원인이 된다. 
- 무거운 시스템에서 가장 좋은 maxIdle 값은 시스템마다 다를 것이다. 그러나 기본값은 좋은 시작 포인트가 된다. 

4. 커넥션 유지를 위한 설정 
4.1 validationQuery
- 기본값 : 없음
- 설명 : validationQuery는 풀에 커넥션을 반환하기 전이나, 풀을 획득하기 전에 커넥션이 valid한지를 검사한다. 이를 지정하고자 하는경우 select쿼리는 반드시 1로만 반환하도록 설정해야한다. 만약 이를 지정하지 않으면 커넥션은 isValid()메소드를 통해서 valid한지 검사하게 된다. 

4.2 validationQueryTimeout
- 기본값 : no timeout
- 설명 : 커넥션 validation 쿼리가 실패하기 전까지 시간을 의미한다. 만약 양수로 설정하면 setQueryTimeout메소드를 통해서 설정이 되며, Statement를 통해서 validation쿼리가 수행된다.

4.3 testOnCreate
- 기본값 : false
- 설명 : 생성된 이후에 객체가 validate되었는지 여부를 나타낸다. 만약 객체가 validate에서 실패한경우 객체 생성은 실패가 된다.

4.4 testOnBorrow
- 기본값 : true
- 설명 : 풀에서 커넥션을 얻어오기전에 객체가 valid한지 검사한다. 만약 객체가 validate에서 실패하면, 풀로 부터 객체를 drop하며, 다른 객체를 얻기위해 시도한다.

4.5 testOnReturn
- 기본값 : false
- 설명 : 풀로 객체를 반환하기 전에 validated된 값인지 검사한다.

4.6 testWhileIdle
- 기본값 : false
- 설명 : idle object evictor에 의해서 검증되어지며, 만약 객체가 검증에서 false가 되면 pool로 부터 드롭한다.

4.7 timeBetweenEvictionRunsMills
- 기본값 : -1
- 설명 : idle object evictor스레드의 실행 주기간격을 설정한다. 양수 값이 아닌경우에는 idle object evictor를 실행하지 않는다.

4.8 numTestsPerEvictionRun
- 기본값 : 3
- 설명 : idle object evictor 스레드가 매번 실행할때 검사할 객체의 개수를 지정한다.

4.9 minEvictableIdleTimeMillis
- 기본값 : 1000 * 60 * 30
- 설명 :풀에 객체가 idle상태로 있을 수 있는 최소한의 시간값을 지정한다.

4.10 softMiniEvictableIdleTimeMillis
- 기본값 : -1
- 설명 : idle collection evictor에 의해서 제거되기 전에 풀에 idle 상태로 남아있을 수 있는 시간을 의마힌다. 이것은 추가적인 상황을 함께 고려되며 적어도 "minIdle"커넥션을 남기도록 한다. miniEvictableIdleTimeMillis가 양수로 설정이 되면 minEvictableIdleTimeMillis는 우선 수행된다. 이것은 idle connections들이 evictor에 의해서 방문되어질때 idle time은 우선 miniEvictableIdleTimeMillis에 대해서 비교되어진다. (풀에 있는 idle 커넥션의 수를 고려하지 않는다.) 그리고 softMinEvictableIdleTimeMillis에 대해서 수행이 되며 minIdle constraint를 포함한다.

4.11 maxConnLifetimeMillis
- 기본값 : -1
- 설명 : 커넥션의 최대 라이프타임을 지정한다. 이 값이 지나게 되면 다음번 activation, passivation,혹은 validation테스트에서 실패하게 된다. zero의 값 혹은 더 적은 값은 라이프 타임이 없는 것을 의미한다.

4.12 logExpiredConnections
- 기본값 : true
- 설명 : 로그 메시지로 maxConnLifetimeMillis를 초과한 경우에 커넥션이 닫혔음을 로그로 남긴다. 이 속성을 false로 설정하여 익스파이어된 커넥션로깅을 막도록 설정할 수 있다.

4.13 connectionInitSqls
- 기본값 : null
- 설명 : SQL statements의 컬렉션으로 물리적 커넥션의 최기화에 사용되어진다. 이것은 커넥션이 처음 생성될때 작용한다. 이 스테이트먼트는 오직 한번만 수행된다. 설정된 커넥션 팩토리가 커넥션을 생성한다.

4.14 lifo
- 기본값 : true
- 설명 : True로 설정하면 borrowObject를 하였을때 가장 최근에 사용된 (즉 마지막에 입력된) 커넥션을 반환한다. (만약 idle 커넥션이 가능한 경우에 가능하다.) False는 풀은 FIFO 큐로 동작한다. 커넥션들은 풀에 들어온 순서대로 풀에서 커넥션을 반환한다.

5. SQL문장에 대한 풀 설정 
5.1 poolPreparedStatements :
- 기본값 : false
- 설명 : 현재 풀을 위한 statement 풀링을 설정한다.

5.2 maxOpenPreparedStatements
- 기본값 : undefined
- 설명 : 최대 개수의 오픈 스테이트먼트를 의미한다. 이것은 statement pool에 동시에 할당될 수 있는 값으로, 음수를 지정하면 제한이 없음을 의미한다.

- 상기 설정은 다음 메소드를 이용하는 경우 풀에 할당된다.
-- public PreparedStatement prepareStatement(String sql)
-- public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency)

NOTE : 
- 커넥션이 다른 statements를 위해서 몇몇의 리소스를 남겨 두었느지 확인하라. Pooling PreparedStatements는 데이터베이스에서 해당 커서를 오픈항 상태로 둘수 있다. 이런경우 Pooling이 커서를 모두 소비해 버릴 수 있다. 특히 maxOpenPreparedStatements가 기본(제한없음)으로 설정된경우 그리고 어플리케이션이 큰 수의 서로다른 PreparedStatements를 하나의 커넥션에서 열고 있는 상태라면 더욱 주의해야한다. 이러한 문제를 피하기 위해서는 maxOpenPreparedStatements는 하나의 커넥션당 열수 있는 최대 커서의 수보다 작은 값을 가지도록 설정해야한다.

6. 나머지 설정 : 
- 아래 참고자료를 참조하자.
참고자료 : https://commons.apache.org/proper/commons-dbcp/configuration.html






[Spring] AOP 정리

[Spring] AOP 정리
AOP란?
AOP (Aspect oriented programming)의 약자이며, Spring framework 의 핵심 기능이다. 
AOP는 프로그램 로직을 concern이라는 작은 단위로 분리한다. 이러한 concern은 프로그램의 여러 위치에서 동작하며 이를 cross-cutting concern이라고한다.

AOP를 이용하면 좋은점 : 

AOP는 어떠한 서비스나 메소드를 호출할때 필요한 수행작업을 하면서도, 핵심 로직에 더 집중할 수 있도록 해주는 특별한 설계기법이다.

예를 들어 햄버거 만드는 과정을 하나의 서비스라고 해보자. 
이때 우리는 하나의 햄버거가 만들어 지는 시간을 측정해야할 필요가 생겼다고 하자. 

기존의 방법대로 프로그래밍을 해야한다고 한다면 우리는 햄버거 만드는 과정에 대한 서비스 자체를 수정해야한다. 
햄버거를 만들기 시작할때 스톱워치를 켜야하고, 햄버거를 만들고, 햄버거를 포장까지 하고난뒤 스톱워치를 정지하여 시간을 측정하는 기록지에 적어야 한다.

스톱워치를 시작하는 행위나 정지하는 행위 그리고 측정내역을 기록하는 행위는 햄버거를 만드는 핵심 서비스 과장과는 완젼히 상관이 없는 행위이다. 

이러한 작업을 수행하기 위해서 우리는 시간을 측정하는 기능을 AOP를 이용하여 기록하게 할 수 있고, 햄버거를 만드는 서비스는 수정할 필요 없다. 
즉, 이러한 핵심작업은 신경쓰지 않고 필요한 작업을 할 수 있고, 신뢰성이 있는 서비스를 제공해 줄 수 있으며, 나아가 햄버거 만드는 작업이 변경이 되더라도 시간을 기록하는 행위 자체를 또다시 분석하거나 손대지 않아도 된다. 

AOP는 핵심 기능에 충실하게 프로그래밍 할 수 있도록 하여, 더 견고하고, 확장성 있는 프로그램을 개발 할 수 있도록 해준다. 

AOP의 용어 :

1. Aspect : 
  - cross-cutting에 필요한 제공되는 API의 셋을 가지는 모듈이다. 
  - 예를 들어 로깅에 필요한 로깅모듈을 AOP의 aspect라고 부른다. 

2. Join point : 
  - AOP aspect 플러그인이 되는 프로그램의 위치를 의미한다. Spring AOP 프레임워크에서 사용되는 위치이다. 

3. Advice : 
  - 메소드가 실행되기 전이나 후에 실제 액션을 의미한다. 이것은 실제 프로그램이 수행되는 코드의 특정 조각이다. 

4. Pointcut : 
  - 이것은 하나 이상의 join point의 셋이다. 이는 표현식이나 패턴을 이용하여 AOP를 수행될 수 있도록 지정한다. 

5. Introduction : 
  - introduction은 존재하는 클래스에 새로운 메소드나 속성들을 추가하도록 허용한다. 

6. Target object : 
  - 하나 혹은 여러개의 aspect에 의해서 advice 받는 객체를 말한다. 이것은 항상 proxy된 객체이다. 

7. Weaving : 
  - Weaving은 aspect를 객체에 연결해주는 과정을 이야기한다. 이것은 컴파일타임에 완료되거나, 로드타임, 혹은 실행시점에 연결이 될 수 있다. 

AOP에서 Advice의 타입 
AOP에서는 5가지 advice 를 가진다. 

1. Before : 
  - 메소드가 실행되기 이전에 실행되는 advice이다. 

2. After : 
  - 메소드가 실행되고 나올때 수행되는 adivce이다. 

3. After-Returning : 
  - 메소드가 완젼히 수행된 이후에 수행되는 advice이다. 

4. After-throwing : 
  - exception이 throw되는 경우에 수행되는 advice이다. 

5. Around : 
  - 메소드가 호출되었을때 시작과 종료시점에 수행된다. 

적용 방식 : 
- Spring framework는 2가지 적용 방식을 제공하고 있다. 

1. XML Schema based : Sample Source Download 
  - Aspects를 일반적인 XML 방식의 설정으로 구현할 수 있도록 한다. 

  - @AspectJ 는 일반적인 자바5 이후의 annotation 을 이용한 선언적인 방식을 사용한다.