본문 바로가기

테크톡 딥다이브

DBCP (Database Connection Pool)

들어가기 앞서 

오늘은 DB의 connection pool에 대해 공부해 볼 예정입니다. 아래 영상 함께 참고해 주시면 감사하겠습니다.

 

https://www.youtube.com/watch?v=zowzVqx3MQ4&t=661s


DB Connection Pool 란?

DB에 쿼리를 요청하기 위해서는 커넥션을 맺어야 한다.

일반적으로 서버에서 데이터베이스에 요청을 하게 되면, Connection을 맺게 됩니다. 이러한 Connection을 맺는 과정에서 서버와 데이터베이스는 TCP 통신을 기반으로 네트워크 통신을 하게 됩니다. (TCP 통신은 높은 신뢰성으로 송수신이 가능!)

 

 

커넥션을 맺기 위해서는 커넥션 생성과 제거 과정을 거쳐야 한다. 너무 비효율적인걸?

하지만 connection을 맺는 과정은 생각보다 오래 걸립니다. connection 생성을 위해서는 3-way handshake, connection 제거를 위해서는 4-way handshake 과정을 수행하게 됩니다. 따라는 매번 요청마다 connection을 열고 닫는 과정을 수행한다면 시간적인 비용이 많이 발생합니다. 

 

미리 커넥션 풀을 맺어 둔다면?

그래서 이러한 문제를 해결 가능한 방법이 DB connection pool 입니다. 처음 백엔드 서버를 띄울때, db connection을 미리 여러개 생성해 둡니다. 따라서 API 요청이 들어온다면 서버는 미리 맺어준 connection 중 하나를 활용합니다. 즉, connection을 재사용하게 되면서 서버의 성능을 개선할 수 있습니다. 

 

 


DB connection 설정 방법

DB connection은 백엔드 서버와 DB 서버 사이의 연결을 의미하기 때문에, 백엔드 서버와 DB 서버 각각에서 설정을 이해하고 있는 것이 중요합니다.

 

max_connections  (DB서버 설정)

DB 서버 설정에 보통 max_connections라고 하여 클라이언트와 맺을수 있는 최대 connection 수를 설정할 수 있습니다. max_connection 수가 4이고, 백엔드 서버의 커넥션 풀 크기도 4로 동일하게 설정하게 되면 어떻게 될까요?

 

이미 연결 가능한 디비 서버의 connection은 백엔드 서버 A와 connection을 모두 맺었기 때문에, 새로운 백엔드 서버 B는 더이상 connection을 맺을수 없습니다. 따라서 max_connections 수를 충분히 적절하게 잘 설정해 주는 것이 중요합니다.

 


wait_timeout  (DB서버 설정)

wait_timeout은 connection이 connection pool에서 놀고 있는 상태 일때, 다시 요청이 올기까지 얼마의 시간을 기다린 뒤에 close할 것인지 결정하는 설정입니다. 

 

백엔드 서버와 디비 서버에서 맺고 있는 커넥션들은 정상적으로 커넥션이 동작하지 않을 수 있습니다.

  • 비정상적인 connection 종료
  • connection 사용 완료 후 반환 되지 않음
  • 네트워크 단절

위와 같은 이유들로 인해 디비 서버는 커넥션이 장애가 발생한지 모르고 계속 connection을 맺으며 자원을 유지하는 상황이 발생합니다. 이러한 장애가 발생한 connection이 점차 증가하게 된다면, 디비 서버는 심각한 성능 장애가 발생합니다. 

 

따라서 디비 서버는 wait_timeout을 설정하여, 일정 시간 동안 디비 서버로 커넥션 사용에 대한 요청이 없다면 connection을 닫아 주는 설정을 통해 해결이 가능합니다.


minimumIdle (백엔드 서버 설정)

minimumIdle은 connection pool에서 유지하는 최소한의 idle connection 수를 의미합니다. 

maximumPoolSize (백엔드 서버 설정)

maximumPoolSize는 pool이 가질 수 있는 최대 connection 수를 의미합니다. 여기서 connection 수는 idle(유휴)와 active(사용중) connection을 합친 개수를 의미합니다.

 

 

여기서 중요한 점은 idle connection 수가 minimumIdle 보다 작고, 전체 connection 수가 maximumPoolSize 보다 작다면 신속하게 추가로 connection을 만든다는 것입니다. 글로는 어떤 의미 인지 어렵죠?

 

minimumIdle (최소 유휴 커넥션 수)가 2로 설정 되어 있기 때문에, 항상 2개의 유휴 커넥션이 커넥션 풀에 존재합니다. 

 

이때 API 요청이 들어오면 어떻게 동작 할까요? 백엔드 서버는 커넥션 풀에서 유휴 커넥션을 획득하게 됩니다. 그러면 유휴 커넥션은 1개가 남게 되고, 설정에 따라 최소 유휴 커넥션은 2개가 되어야 하기 때문에, 유휴 커넥션이 하나더 생성 됩니다.

 

 

API 요청이 계속 들어오게 되면 어떻게 될까요? 여기서 중요한 점은 minimumIdle 설정에 따라 계속 유휴 커넥션을 2개로 맞추지만, 어느 순간 API 요청이 계속 들어와 전체 커넥션 수가 4개 되면, maximumPoolSize 설정에 따라 더 이상 유휴 커넥션을 생성하지 않습니다.

 

minimumIdel == maximumPoolSize 

HikariCP는 minimumIdle 설정과 maximumPoolSize 설정을 동일한 값을 사용하도록 권장하고 있습니다. (default 값도 동일하게 설정 되어 있습니다.)

 

pool size를 고정시킨다는 의미 입니다. 이렇게 권장 하는 이유는 두 설정이 다르게 설정 되어 있다면, 트래픽이 순간적으로 몰려 올때 커넥션을 만드는 시간 때문에 응답이 늦어 질 수 있기 때문입니다.


maxLifetime (백엔드 서버 설정)

maxLifetime은 pool에서 connection의 최대 수명을 설정하는 것으로, maxLifetime을 넘기면 유휴(idle) connection일 경우 pool에서 바로 제거 됩니다. 또한 active 상태일 경우 pool로 반환된 후에 제거 됩니다.

 

여기서 중요한 부분은 pool로 커넥션이 반환이 되지 않으면, maxLifetime은 동작하지 않게 됩니다. 백엔드 서버 커넥션 중 하나가 장애로 인해 정상적으로 반환 되지 않는다면, maxLifetime은 pool로 반환이 되어야 커넥션을 제거하지만, 반환되지 않아 제거 되지 않습니다.

 

DB서버는 wait_timeout 설정으로 인해 일정 시간 동안 요청이 오지 않으면 커넥션을 끊어 버립니다. 하지만 이때 해당 커넥션을 통해 api 요청이 들어오면 exception(장애)이 발생하게 됩니다. 따라서 connection을 pool에 잘 반환하여 누수가 발생하지 않도록 하는것이 중요합니다.

 

maxLifetime < wait_time

또한 백엔드 서버 maxLifetime은 DB의 wait_time보다 작게 설정한는 것을 권장합니다. 둘다 60초로 동일하게 설정 되어 있다면, 59초에 API 요청이 들어오고, connection을 통해 통신을 하려는 순간 60초가 되어 DB는 커넥션을 끊어 버립니다. 따라서 해당 요청 역시 exception(장애)이 발생할 수도 있습니다. 

 


connectionTimeout (백엔드 서버 설정)

connectionTimeout은 pool에서 connection을 받기 위한 대기 시간입니다. 갑자기 요청이 밀려와 백엔드 서버의 커넥션을 모두 사용하고 있을때, 무한정 기다리고 있을수 없기 때문에 대기하고 있는 상황을 종료시켜 줍니다.