본문 바로가기
Database

DBCP

by 홍굴이 2021. 12. 23.

 

왜 ?

운영 중 에러로그로 식별할 수 없는 이슈인 'out of memory' 가 발생하거나, DB서버에서부터 발생한 장애로 서버가 뻗는 경우는 대부분 WAS와 DB서버 간 이슈이다.

 

데이터베이스에서 데이터를 읽어올 때, 가장 비용이 큰 부분은 서버가 물리적으로 DB 서버가 최초로 연결되어 Connetcion을 생성하는 부분이다.

 

JDBC 사용 시 DB 연결 과정

  1. DB 접속을 위한 JDBC 드라이버 로드
  2. getConnection 메서드로부터 Connection 객체 생성
  3. 쿼리 수행을 위해 PreparedStatement 객체 생성 후 쿼리 수행
  4. 처리가 완료되면 사용된 리소스들을 close 하여 반환

정의

DataBase Connection Pool의 약자

데이터베이스와 연결된 Connection을 미리 만들어 놓고 Pool 속에 저장해 두고 있다가 필요할 때 Connection 을 Pool 에서 가져와 사용하고 Pool 다시 반환하는 기법

남아있는 Connection이 없다면 해당 클라이언트는 대기 상태로 전환하고, Connection이 다시 Pool에 들어오면 대기 상태에 있던 클라이언트에게 순서대로 제공한다.

 

WAS가 실행 될 때 애플리케이션에서는 Connection Pool 라이브러리를 통해 Connection Pool 구현체를 사용할 수가 있는데, Apache의 Commons DBCP가 오픈소스 라이브러리로 제공되고 있다.

https://commons.apache.org/

 

Apache Commons – Apache Commons

Welcome to Apache Commons Apache Commons is an Apache project focused on all aspects of reusable Java components. The Apache Commons project is composed of three parts: The Commons Proper - A repository of reusable Java components. The Commons Sandbox - A

commons.apache.org


커넥션 풀의 저장 구조

속성

속성 이름 설명
initialSize 최초로 getConnection() 메서드를 호출할 때 커넥션 풀에 채워 넣을 커넥션 개수
maxSize 동시에 사용할 수 있는 최대 커넥션 개수(기본값 8)
maxIdle 커넥션 풀에 반납할 때 최대로 유지될 수 있는 커넥션 개수(기본값 8)
즉, 사용되지 않고 풀에 저장될 수 있는 최대 커넥션 개수
minIdle 최소한으로 유지할 커넥션 개수(기본값 0)

4개 커넥션이 활성화된 상태의 그림

속성 설정 조건

  1. maxActive >= initialSize
    • 최대 커넥션 개수는 초기에 생성할 커넥션 개수와 같거나 크게 설정
    • 예를 들어, maxActive=5 , initialSize = 10 이라고 가정하면, 최초에 커넥션을 생성할 때 initialSize 값이 최대 커넥션 개수인 maxActive 값보다 커서 논리적으로 오류가 발생함.
  2. maxIdle >= minIdle
    • maxIdle < minIdle로 설정할 수는 있지만 최솟값이 최댓값보다 커서 논리적으로 오류가 있는 설정이다.
  3. maxActive = maxIdle
    • maxActive=10 , maxIdle=5 라고 가정하면, 커넥션을 5개 사용하고 있는 상황에서 1개의 커넥션이 추가로 요청된다면 maxActive는 10이므로 1개의 추가 커넥션을 데이터베이스 연결한 후 풀은 비즈니스 로직으로 커넥션을 전달한다.
      이후 비즈니스 로직이 커넥션을 사용 후 풀에 반납할 경우 maxIdle=5에 영향을 받아 커넥션을 닫아버리므로, 일부 커넥션을 매번 생성했다 닫는 비용이 발생할 수 있다.

initialSize, maxActive, maxIdle 그리고 minIdle 항목을 동일한 값으로 통일해도 상관없다.

 

커넥션 개수와 관련된 가장 중요한 성능 요소는 일반적으로 최대 커넥션의 개수이다.

maxActive값은 DBMS의 설정과 애플리케이션 서버의 개수, Tomcat에서 동시에 처리할 수 있는 사용자 수 등을 고려해서 설정해야한다.

DBMS가 수용할 수 있는 커넥션 개수를 확인한 후에 애플리케이션 서버 인스턴스 1개가 사용하기에 적절한 개수를 설정한다.

사용자가 몰려서 커넥션을 많이 사용할 때 maxActive 값이 크지 않다면 병목 지점이 될 수 있다.

반대로 사용자가 적어서 사용 중인 커넥션이 많지 않을 때는 maxActive 값을 지나치게 작게 설정하지 않는 한 성능에 큰 영향이 없다.

 

Commons DBCP에서는 DBMS에 로그인을 시도하는 커넥션도 사용 중인 것으로 간주하기 때문에 DBMS에 로그인을 시도하고 있는 상태로 무한히 대기한다면, 애플리케이션에서 모든 커넥션이 사용 중인 상태가 돼 새로운 요청을 처리하지 못할 수도 있다.

그래서 JDBC 드라이버에서 설정하는 loginTimeOut 속성같은 타임아웃 속성을 설정하는 것이 좋다.

 

커넥션을 얻기 전 대기 시간

maxWait 속성은 커넥션 풀 안의 커넥션이 고갈됐을 때 커넥션 반납을 대기하는 시간(밀리초)이며 기본값은 무한정이다.

일반적인 상황은 문제가 안되지만, 사용자가 갑자기 급증하거나 DBMS 장애가 발생했을 때 장애를 더욱 크게 확산 시킬 수 있어 주의해야한다.

 

적절한 maxWait 값 설정

[예시 값]
maxActive = 5
maxIdle = 5
minIdle 5
[예시 상황]
사용자 요청 A는 요청 하나에 쿼리 10개를 실행
각 쿼리의 평균 실행 시간은 50밀리초 => 10개 쿼리의 실행 시간 = 500밀리초

앞의 가정에서 시스템 전체의 TPS(Transactional per Second)는 요청 하나의 응답 시간이 500밀리초이기 때문에 커넥션 풀에 이용 가능한 유휴 상태의 커넥션이 5개일 때 동시에 5개 요청을 500밀리초 동안 처리한다.

따라서 1초 동안에는 10개의 요청을 처리할 수 있고 성능 지수는 10TPS 이다.

 

TPS와 커넥션 개수의 관계를 살펴보면, 1번부터 10번까지 총 10개의 요청이 동시에 들어오면, 6번부터 10번까지의 요청은 여분의 커넥션이 생길 때까지 maxWait값만큼 기다린다.

 

이를 해결하는 가장 쉬운 방법은 maxActive 값을 높여서 커넥션 풀의 개수를 늘리면 된다.

즉, 커넥션 개수를 5에서 10으로 늘리면 10TPS 에서 20TPS로 증가한다.

 

하지만, 일반적으로 DBMS 리소스는 다른 서비스와 공유해 사용하는 경우가 많기 때문에 무조건 커넥션 개수를 크게 설정할 수 없는 상황이 많다. 따라서 예상 접속자 수와 서비스의 실제 부하를 측정해 최적값을 설정하는 것이 중요하다. 

즉, 대기 시간 값 조절이 무한히 커넥션 개수를 늘리지 않고 최적의 시스템 환경을 구축하는데 중요한 역할을 한다.

 

maxWait 값 고려시 Tomcat 동작 방식

Tomcat은 스레드 기반으로 동작해 사용자의 요청을 처리한다.

Commons DBCP가 커넥션 풀을 가지고 있는 것처럼 Tomcat도 내부에 스레드 풀을 가지고 있어 사용자의 요청이 들어올 때마다 스레드 풀에서 하나씩 스레드를 꺼내서 요청을 처리한다.

 

예를 들어, maxWait 값이 10,000밀리초면 처리량을 넘어서는 요청의 스레드는 10초 동안 대기 상태에 있게 된다.

그리고 사용자의 요청이 계속 증가하면 결국 Tomcat 스레드 풀의 모든 스레드가 소진 돼 Tomcat은 오류를 출력하며 응답을 멈출 것 이다.

또한, 10초 동안 대기 상태가 해제되고 커넥션을 획득해 요청을 처리하고 응답을 하여도 사용자는 이미 떠났을 수도 있다는 점이다.

(사용자는 클릭 후 2~3초 이내에 반응이 없으면 새로고침하거나 다른 일을 한다.)

결국 의미없는 요청에 응답하기 위해 자원을 낭비한게 된다.

 

반대로 너무 작게 설정하면 과부하 시 커넥션 풀에 여분의 커넥션이 없을 때마다 오류가 반환될 것이다.

 

정리

maxWait 값도 사용자의 대기 가능한 시간 같은, 애플리케이션의 특성과 다른 주변의 설정, 자원의 상황 등을 고려해 판단해야 한다. 만약 갑작스럽게 사용자가 증가해 maxWait 값 안에 커넥션을 얻지 못하는 빈도가 늘어난다면 maxWait 값을 더 줄여서 시스템에서 사용하는 스레드가 한도에 도달하지 않도록 방어할 수 있다. 이런 상황이 자주 있다면 Commons DBCP의 maxActive 값과 Tomcat의 maxThread 값을 동시에 늘이는 것을 고려한다.

 

내가 생각하기에 가장 좋은 방법은 애플리케이션을 실제 운영할 시스템 환경에서 성능 테스트를 진행하는 것이다. 성능 테스트를 진행하면서 지금까지 살펴본 DBCP에 대한 원리와 설정을 위한 값들을 복기하면서 시스템 환경에 최적화된 값을 찾아 내는 것이 좋을 것 같다.

그리고, WAS의 스레드 개수는 커넥션 개수보다 많아야 하는 것이 좋을 것 같다.

왜냐하면, 모든 요청이 DB에 접근하는 것은 아니기 때문이다.


HikariCP

SpringBoot 2.0 의 default DBCP는 HikariCP이다.

HikariCP 는 Commons-DBCP가 가지고있는 initialSize 같은 속성이 없다.

min 사이즈로 초기에 지정하는 것으로 알고 있다.

 

속성 가이드

  1. auto-commit (default : true)
    • 커넥션이 종료되거나 풀에 반환될 때, 커넥션에 속해있는 transaction을 commit 할지 결정
  2. connection-timeout (default : 30000 - 30초)
    • 풀에서 커넥션을 얻어오기전까지 기다리는 최대 시간
    • 허용 가능한 wait time을 초과하면 SQLException을 던짐
  3. idle-timeout (default : 600000 - 10분)
    • 풀에 일을 안하는 커넥션을 유지하는 시간
    • 이 옵션은 minimum-idle이 maximum-pool-size보다 작게 설정되어 있을 때만 설정
  4. max-lifetime (default : 1800000 - 30분)
    • 커넥션 풀에서 살아있을 수 있는 커넥션의 최대 수명시간
  5. minimum-idle (default: maximum-pool-size)
    • 아무런 일을 하지 않아도 적어도 이 옵션에 설정 값 size로 커넥션들을 유지해주는 설정
    • 최적의 성능과 응답성을 요구한다면 이 값은 설정하지 않는것이 좋음
  6. maximum-pool-size (default: 10)
    • 풀에 유지시킬 수 있는 최대 커넥션 수
  7. transaction-isolation (default: none)
    • 커넥션에 지정된 트랜잭션 격리 수준을 지정한다.

 

 

참조

https://d2.naver.com/helloworld/5102792

https://www.holaxprogramming.com/2013/01/10/devops-how-to-manage-dbcp/

 

DB Connection Pool에 대한 이야기 · 안녕 프로그래밍

웹 애플리케이션을 운영하다 보면 에러 로그로는 식별 할 수 없는 잠재적인 이슈가 발생 할 때가 있다. 애플리케이션내의 오류가 명확히 확인이 되지 않은 상태에서 Out of memory가 발생 하거나, DB

www.holaxprogramming.com

https://kchanguk.tistory.com/14

 

DBCP

DBCP란 DBCP의 개념 DBCP란 DataBase Connection Pool의 약자로 DB와 커넥션을 맺고 있는 객체를 관리하는 역할을 합니다. 일반적으로 JDBC를 이용한다면 아래와 같은 순서로 DB에 접속합니다. DB 접속을 위한

kchanguk.tistory.com

https://blue-mina.tistory.com/19

 

[DB] DBCP란? (사용이유 및 고려사항)

DBCP란? 운영 중에 에러로그로 식별할 수 없는 이슈인 out of memory 가 발생하거나, DB서버에서부터 발생한 장애로 서버가 뻗는 경우는 대부분 WAS와 DB 서버 간의 이슈 즉, DBCP 와 관련된 이슈입니다.

blue-mina.tistory.com

https://brownbears.tistory.com/289

 

[DB]Connection Pool

Connection Pool이란? 서버는 동시에 사용할 수 있는 사람의 수라는 개념이 존재합니다. 일반적인 Connection Pool을 이용하면 동시 접속자 수를 벗어나게 될 경우 에러(예외)가 발생하게 됩니다. 예외가

brownbears.tistory.com

https://freedeveloper.tistory.com/250

 

[SpringBoot HikariCp] HikariCP 속성 설정 가이드

[HikariCp Preperty] https://effectivesquid.tistory.com/entry/HikariCP-세팅시-옵션-설명 http://blog.naver.com/PostView.nhn?blogId=hanajava&logNo=221570132498&parentCategoryNo=40&categoryNo=&viewDate=..

freedeveloper.tistory.com

 

 

댓글