커넥션의 개수
커넥션 풀의 저장 구조
커넥션 개수를 제대로 설정하려면 Commons DBCP 내부에서 커넥션 풀이 어떤 구조로 저장되는지 이해해야 한다. Commons DBCP는 그림 1처럼 commons-pool에서 제공하는 리소스 풀의 기능을 이용한다.
그림 1 commons-pool의 GeneriObjectPool
커넥션 생성은 Commons DBCP에서 이루어진다. Commons DBCP는 PoolableConnection 타입의 커넥션을 생성하고 생성한 커넥션에 ConnectionEventListener를 등록한다. ConnectionEventListener에는 애플리케이션이 사용한 커넥션을 풀로 반환하기 위해 JDBC 드라이버가 호출할 수 있는 콜백 메서드가 있다. 이렇게 생성된 커넥션은 commons-pool의 addObject() 메서드로 커넥션 풀에 추가된다. 이때 commons-pool은 내부적으로 현재 시간을 담고 있는 타임스탬프와 추가된 커넥션의 레퍼런스를 한 쌍으로 하는 ObjectTimestampPair라는 자료구조를 생성한다. 그리고 이들을 LIFO(last in first out) 형태의 CursorableLinkedList로 관리한다.
그림 1의 구조를 기억한다면 Commons DBCP에서 설정할 수 있는 속성 값에 따라서 내부에 저장된 커넥션의 개수가 어떻게 달라지는지 이해하는 데 도움이 될 것이다.
커넥션 개수 관련 속성
커넥션의 개수는 BasicDataSource 클래스의 다음 속성으로 지정할 수 있다.
표 3 BasicDataSource 클래스의 커넥션 개수 지정 속성
속성 이름설명
initialSize | BasicDataSource 클래스 생성 후 최초로 getConnection() 메서드를 호출할 때 커넥션 풀에 채워 넣을 커넥션 개수 |
maxActive | 동시에 사용할 수 있는 최대 커넥션 개수(기본값: 8) |
maxIdle | 커넥션 풀에 반납할 때 최대로 유지될 수 있는 커넥션 개수(기본값: 8) |
minIdle | 최소한으로 유지할 커넥션 개수(기본값: 0) |
만약 8개의 커넥션을 최대로 활용할 수 있을 때 4개는 사용 중이고 4개는 대기 중인 상태라면 커넥션 풀의 상태는 그림 2와 같을 것이다.
그림 2 일부 커넥션이 활성화된 상태
커넥션 개수와 관련된 속성은 다음과 같은 조건을 만족시켜야 한다.
- maxActive >= initialSize
maxActive = 10이고 initialSize = 20이라고 가정하면 최초에 커넥션을 생성할 때 initialSize 값이 최대 커넥션 개수인 maxActive 값보다 커서 논리적으로 오류가 있는 설정이다. - maxIdle >= minIdle
maxIdle < minIdle로 설정할 수는 있지만 최솟값이 최댓값보다 커서 논리적으로 오류가 있는 설정이다. - maxActive = maxIdle
maxActive 값과 maxIdle 값이 같은 것이 바람직하다. maxActive = 10이고 maxIdle = 5라고 가정해 보자. 항상 커넥션을 동시에 5개는 사용하고 있는 상황에서 1개의 커넥션이 추가로 요청된다면 maxActive = 10이므로 1개의 추가 커넥션을 데이터베이스에 연결한 후 풀은 비즈니스 로직으로 커넥션을 전달한다. 이후 비즈니스 로직이 커넥션을 사용 후 풀에 반납할 경우, maxIdle=5에 영향을 받아 커넥션을 실제로 닫아버리므로, 일부 커넥션을 매번 생성했다 닫는 비용이 발생할 수 있다.
initialSize와 maxActive, maxIdle, minIdle 항목을 동일한 값으로 통일해도 무방하다. 커넥션 개수와 관련된 가장 중요한 성능 요소는 일반적으로 커넥션의 최대 개수다. 4개 항목의 설정 값 차이는 성능을 좌우하는 중요 변수는 아니다.
maxActive 값은 DBMS의 설정과 애플리케이션 서버의 개수, Apache, Tomcat에서 동시에 처리할 수 있는 사용자 수 등을 고려해서 설정해야 한다. DBMS가 수용할 수 있는 커넥션 개수를 확인한 후에 애플리케이션 서버 인스턴스 1개가 사용하기에 적절한 개수를 설정한다. 사용자가 몰려서 커넥션을 많이 사용할 때는 maxActive 값이 충분히 크지 않다면 병목 지점이 될 수 있다. 반대로 사용자가 적어서 사용 중인 커넥션이 많지 않은 시스템에서는 maxActive 값을 지나치게 작게 설정하지 않는 한 성능에 큰 영향이 없다.
Commons DBCP에서는 DBMS에 로그인을 시도하고 있는 커넥션도 사용 중인 것으로 간주한다. 만약 DBMS에 로그인을 시도하고 있는 상태에서 무한으로 대기하고 있다면, 애플리케이션에서 모든 커넥션이 사용 중인 상태가 돼 새로운 요청을 처리하지 못할 수도 있다. 이런 경우 장애 확산을 최소화하려면 Microsoft SQL Server의 JDBC 드라이버에서 설정하는 loginTimeOut 속성같은 JDBC 드라이버별 타임아웃 속성을 설정하는 것이 좋다. JDBC의 타임아웃에 관한 자세한 내용은 "JDBC Internal - 타임아웃의 이해" 글을 참고한다.
커넥션을 얻기 전 대기 시간
BasicDataSource 클래스의 maxWait 속성은 커넥션 풀 안의 커넥션이 고갈됐을 때 커넥션 반납을 대기하는 시간(밀리초)이며 기본값은 무한정이다. maxWait 속성을 적절하게 설정하지 않아도 일반적인 상황에서는 큰 문제가 되지 않는다. 하지만 사용자가 갑자기 급증하거나 DBMS에 장애가 발생했을 때 장애를 더욱 크게 확산시킬 수 있어 주의해야 한다.
적절한 maxWait 값을 설정하려면 TPS(transaction per seconds)와 Tomcat에서 처리 가능한 스레드 개수 등을 이해해야 한다.
'헷갈리는 것들 공부' 카테고리의 다른 글
JWT(Json Web Token) 그게 대체 뭔데? (0) | 2021.11.16 |
---|---|
GET과 POST의 차이 (0) | 2021.10.15 |
HTTP, 그리고 HTTPS의 이해 (2) | 2021.09.06 |
[jQuery] attr()과 prop()의 차이점은 무엇일까? (0) | 2021.09.01 |
JSON value 뽑아내기, console로 찍어보기 (0) | 2021.08.27 |
댓글