DBCP 는 왜 필요한가?
DBCP 가 없는 상태에서 클라이언트 로 부터 Request 요청을 받고 특정 쿼리 조회시 Application Server 와 DB Server 어떻게 통신을 하게 되는지 알아보겠습니다.
먼저 클라이언트 로 부터 Request 요청을 들어오고 특정 쿼리를 조회 하기 위해 DB 서버에 요청을 했습니다.
이후에 요청을 받고 나서 데이터를 가공해 클라이언트에 응답하는 형식 입니다.
결국 Application Server 에서 쿼리 조회를 하기 위해서는 DB Server 에 요청 및 응답이 발생 됩니다. 즉 네트워크 통신이 발생되는데 이때 일반적으로 TCP 기반 형식으로 이루어 집니다.
처음 DB Server 에 쿼리 조회 하기 위해 먼저 Connection 을 Open 하게 되면서 3 way handshake 가 발생됩니다. 그리고 나서 요청이 발생되는데요.
이후 DB 서버에서 요청 받는 후 특정 쿼리를 분석하고 데이터를 가져와 응답하고 나서 연결 되었는 Connection 을 Close 을 하게 됩니다. 이때 4 way handshake 가 발생 됩니다.
즉 TCP 는 안정적이고 신뢰성 있는 통신을 하기 위해 이러한 과정이 필요하게 됩니다.
일반적인 서비스 경우 사용자가 해당 서비스를 이용하기 위해 빈번하게 어떤 데이터를 조회 하기 위해 위에 설명한 내용이 반복적으로 발생 된다고 보면 됩니다.
즉 DB Server 와 통신하기 위해 Connection 을 Open 하고 Close 하는 과정 이렇게 반복적으로 발생시 시간적인 비용이 많이 발생되지 않을 수 없습니다.
DBCP 로 이 문제를 해결해보자
초기 Application Server 를 띄울때 Connection 을 미리 DB Server 연결을 맺고 시작을 하게 됩니다.
이렇게 연결된 DB Connection 들을 Pool 로 관리 하게 되는데요.
이후 클라이언트 부터 요청이 들어오면 특정 DB Server 에 특정 쿼리 조회 요청시 일반적으로 그전에 Connection 연결을 맺어주었는데
이미 맺어진 Connection 을 이용해서 쿼리 조회 하게 됩니다. 즉 그림에 보시면 4개의 Connection 에서 Idle 상태인 하나인 Connection 을 가져와서 쿼리를 조회 합니다.
이후 쿼리 조회가 마무리 된다면 가져왔던 Connection 을 다시 Pool 에 반납하는 형식 입니다.
이렇게 처리하게 된다면 쿼리 조회 할때마다 Connection 맺어주고 쿼리 조회 및 쿼리 응답 완료시 Connection 끊어 주는 과정을 절약 할 수 있어 시간적인 비용을 절감 할 수 있게 됩니다.
Pool 로 통해 Connection 을 관리 하게 되는데 이를 Database Connection Pool (DBCP) 이라고 합니다.
DBCP 설정 (DB Server 설정)
설명에 앞써 보편적으로 많이 사용되는 Spring Boot 에서 많이 사용되고 있는 Hikari CP 그리고 DB 서버는 Mysql 기준으로 설명 하고자 합니다.
max_connections
해당 디비 설정은 client 하고 최대 Connection 할 수 있는 수 입니다.
예를들어서 max_connections 값을 4라고 설정 하게 되면 Client (Spring Boot Application Server) 하고 맺을수 있는 최대 Connection 수가 4개 이라는 의미 입니다.
만약 4개를 초과 하게 된다면 “Too many connections” 에러가 발생 하게 됩니다.
즉 트래픽이 많이 발생되어서 기존에 max_connections 수를 4개로 유지 한 상태에서 생각없이 Spring Boot Application Server 만 늘릴 경우
새로 생성된 서버에서 4개의 Connection 을 더 맺어주기를 바라고 있지만 max_connections 수가 4 이기 때문에 연결하지 못하고 에러가 발생됩니다.
이 문제를 해결 하기 위해서는 최소 max_connections 수를 8개 이상을 설정 해줘야 무리 없이 진행 하게 됩니다.
wait_timeout
Application Server 와 Mysql Server 하고 connection 맺은 시점 부터 해당 connection 이 inactive 할때 다시 요청을 들어오기 까지 설정 시간 만큼
기다린 다음에 Connection 을 Close 할것인가 의미 입니다.
예를들어 wait_timeout 설정은 300초로 지정을 했다고 했을때 최초 connection 을 맺은 시점 부터 300초 동안 계속 Idle 상태 (Mysql Connection 기준) 이라고 가정시
연결을 끊도록 합니다. 왜 이런 행동이 필요한다면 Mysql 서버 기준으로 connection 은 Idle 상태에서 연결된 Application Server 의 Connection 은
Connection 을 가져와서 사용 한 뒤 반납을 못 하는 에러가 발생시 계속 기다리거나 점유 하게 된다면 문제가 발생 됩니다. 특히 이러한 문제가 다른 Connection 에서도 동일한 문제가 발생되면 전체적으로 Mysql Server 에 안좋은 일이 발생 됩니다.
이런 상황을 대비해 Mysql Server 기준으로 특정 시간이 초과 되면 연결을 끊어질수 있도록 설정 해야 합니다.
만약 설정한 300초가 299초에 Mysql Server 로 요청이 들어오면 다시 0초 부터 초기화 하게 되고 그때부터 다시 카운트가 시작 됩니다.
DBCP 설정 (Client 설정)
minimumidle
maximumPoolSize
minimumidle 은 DBCP 에서 유지 하는 최소 Idle Connection 갯수를 의미 합니다.
minimumidle 설명하기 위해 maximumPoolSize 설정 값도 함께 알아보자 합니다.
maximumPoolSize 는 DBCP 에서 유지 하는 최대 Connection 갯수 의미 합니다.
minimumidle: 2, maximumPoolSize: 4 설정값으로 설명 하고자 합니다.
초기 Sprong Boot Server 가 띄우게 된다면 minimumidle 값 2로 인해서 Mysql Server 와 최소 2개 Connection 만 연결 하도록 합니다.
이후 Mysql Server 측면에서 Client 로부터 요청 1개가 들어오면 미리 연결된 Connection 통해 사용하게 되고 동시에
minimumidle 값 2로 셋팅 했기 때문에 이를 유지 하기 위해 한개 Connection 을 새로 생성하게 됩니다.
다시 동시에 Client 로부터 요청 1개가 들어오면 미리 연결된 Connection 통해 사용하고 초기 설정한 minimumidle 값 2로 인해 한개 Connection 을 새로 생성 하게 됩니다.
다시 Client 로부터 요청 1개가 더 들어오면 minimumidle 값 2로 인해 한개 Connection 이 추가 해야 겠지만
maximumPoolSize 값 4개로 인해 4개 이상 더 생성 할 수가 없어서 4개 Connection 중 3개는 Active, 나머지 1개가 Idel 상태가 됩니다.
이후에 트래픽이 없어지면 4개 Connection 중 minimumidle 값 2로 인해 2개 Connection 을 끊어지게 됩니다.
Hikari CP 메뉴얼에서 minimumidle 값 추천값은 maximumPoolSize 값과 동일하게 설정 해야 한다는 것이 있습니다.
왜냐하면 갑자스러운 대량의 트래픽을 대비하기 위해 (Connection 을 맺어주는 과정을 비용이 많이 들기 때문) minimumidle 값을 maximumPoolSize 값과 동일하게 설정하면 좋습니다.
maxLifetime
maxLifetime 은 DBCP 에서 Connection 수명을 의미 합니다.
특정 Connection 이 설정한 maxLifetime 시간을 초과되면 (특정 Connection 이 Idle 상태일 경우) Connection 을 제거 하고 바로 Connection 을 새로 생성 하게 됩니다.
만약 특정 Connection 이 Idle 상태가 아니라 Active 상태이면 (해당 Connection 을 연결 맺을 시점로 부터 설정한 maxLifetime 값 보다 지났음에도 불과하고) 해당 Connection 을 반납 하면 다시 시간 초기화 하게 됩니다.
즉 Active 상태이면 시간 카운팅을 하지 않고 connection 반납시 다시 시간 초기화 하게 됩니다.
이러한 성격 때문에 만약 maxLifetime 값을 29초로 설정 했다고 하면 특정 Connection 을 최초 생성 시점으로 부터 28초 지난 시점에 사용 한다고 예를 들면 사용 후 특정 문제로 반납하지 않고 계속 Active 상태가 되어버리면
계속 해당 Connection 은 불능 상태가 되어 버립니다. 이러한 케이스를 해결하기 위해서는 앞써 이야기한 Mysql DB Server 설정 중 wait_timeout 을 이용 해야 합니다.
maxLifetime 값을 29초로 설정하고 wait_timeout 값을 30초로 설정 한다고 하면 해당 Connection 을 연결 맺을 시점로 부터 20초가 지난 시점에
해당 connection 사용하고 특정 문제로 계속 반납하지 계속 못한 상태이면 wait_timeout 설정 한 30초로 인해 30초가 지나면 Connection 은 제거 하게 됩니다.
maxLifetime 설정 값은 가장 이상적인 값 경우 Mysql Server 설정 값 중 wait_timeout 값 몇 초 짧게 하는 것이 추천 합니다.
만약 maxLifetime 값을 30초로 설정하고 wait_timeout 값을 30초로 설정 한다고 하겠습니다. 특정 Connection 이 최초 생성한 시점으로 부터 29초가 지났을 시점에
Connection 을 가져다 사용하게 될때 불미스럽게도 Mysql Server 까지 도착하지 못한 상태에서 30초가 지났으면 Mysql DB Server 에서 설정한 wait_timeout 으로 인해
해당 connection 은 제거 하게 됩니다. 즉 Mysql Server 로 도착하기 전에 Connection 은 제거 되어버려서 안정적인 쿼리 조회가 실패 하게 됩니다.
그래서 이러한 문제를 해결 하기 위해서는 wait_timeout 값을 30초로 설정 했다면 maxLifetime 값은 몇초 짧게 설정하는 것이 좋습니다.
connectionTimeout
DB Hikari CP 설정 값 중 connectionTimeout 은 Pool 에서 Connection 을 가져오기 위한 대기 시간을 말 합니다.
예를들어 connectionTimeout 값을 10초, minimumIdle 하고 maximumPoolSize 값을 4개로 설정 한다고 하면
기존 4개 Connection 을 모두 Active 상태에서 계속되는 요청으로 Connection 을 사용하고 할때 이때 설정한 connectionTimeout 10초가 지나도
반납 하지 않는 경우 Exception 이 발생 하게 됩니다.
실제로 서비스 업체마다 이 시간은 각각 다르게 전략을 세우게 됩니다. 예를들어 실제 사용자가 사용하는 입장이라면 이 시간은 적절하게 설정 해야 합니다.
Copyright 201- syh8088. 무단 전재 및 재배포 금지. 출처 표기 시 인용 가능.