DB Connection Pool 고갈이 되면 무슨 일이 벌어질까?
대부분의 웹 애플리케이션은 DB Connection Pool을 사용한다. DB 커넥션 풀 덕분에 동시 사용자 요청을 빠르게 처리할 수 있다.
하지만 어느 순간, 예상치 못한 상황이 발생한다.
그 순간중 하나가 바로 커넥션 풀 고갈(Connection Exhaustion) 이다.
- DB 연결 대기 시간이 급격히 증가한다
- 요청이 지연된다
- 최악의 경우 애플리케이션 전체가 다운된다.
그렇다면 DB Connection Pool에 대해서 알아보자.
DB Connection Pool 이란?
DB 연결(Connection)을 매번 새로 열고 닫으면 비용이 크기 때문에, 일정 수의 커넥션을 미리 생성해 풀(pool)에 담아두고 재사용하는 구조이다.
특징 | 설명 |
커넥션 생성 비용 절감 | 연결이 미리 준비되어 빠른 응답 가능 |
커넥션 수 제한 가능 | DB에 과한 부하를 주지 않음 |
대기시간 단축 | 필요시 즉시 커넥션 제공 가능 |
인기 있는 커넥션 풀 라이브러리는 다음과 같다.
- HikariCP (스프링 부트 기본)
- Tomcat JDBC Pool
- DBCP2 (Apache)
그렇다면 커넥션 풀 고갈이란 무엇일까?
커넥션 풀 고갈(Connection Pool Exhaustion) 이란?
커넥션 풀 안의 커넥션이 모두 사용 중이어서, 새로운 요청에 빌려줄 커넥션이 없는 상태를 말한다.
발생 과정을 간략하게 살펴보면
- 사용자는 요청을 보낸다.
- 서버는 DB 작업을 하려고 커넥션을 풀에서 꺼낸다.
- 풀에 남은 커넥션이 없다.
- 요청은 대기(wait) 하거나, 시간 초과(timeout) 되며 실패한다.
커넥션 풀이 고갈되면
현상 | 설명 |
서버 응답 지연 | 커넥션을 얻을 때까지 기다리면서 전체 응답이 느려진다 |
타임아웃 발생 | 일정 시간 안에 커넥션을 못 얻으면 에러가 발생한다 |
DB 부하 급증 또는 다운 | 일부 트랜잭션이 커넥션을 오래 점유하면 DB에 과부화 |
서버 과부화/장애 | 요청이 몰리면서 스레드/큐가 포화, 시스템 전반 문제 발생 |
이런 현상들이 발생할 수 있다.
스프링부트 + HikariCP 에서 고갈상황을 억지로 만들어 보자.
spring.datasource.hikari.maximum-pool-size: 10
spring.datasource.hikari.connection-timeout: 30000
위 설정을 추가해
- 최대 10개의 커넥션만 풀에 존재시키고
- 커넥션을 못 빌리면 최대 30초 동안 대기 후 타임아웃이 발생
만약 동시에 요청이 50개 들어오고, 각각 DB 작업을 오래 잡고 있으면 어떻게 될까?
결과 :
- 처음 10개는 커넥션 얻고 정상 처리
- 나머지 40개는 커넥션 풀에서 대기
- 일부 요청은 30초 대기하다 타임아웃 발생
- 서버 전체가 느려지고 장애 징후가 보인다.
이런 커넥션 풀 고갈의 주요 원인은 다음과 같은 것들이 있다.
1. 커넥션 미반납(Conneciton Lock)
val conn = dataSource.connection
// ... 쿼리 수행
// conn.close() 빠뜨림!!
close()를 호출하지 않으면, 커넥션 풀로 반환되지 않는다. 시간이 지나면 커넥션이 모두 소비되고 고갈된다.
항상 try-with-resources 또는 finally 블록에서 명시적으로 close 해야 한다.
2. 긴 트랜잭션(Long Transaction)
트랜잭션 안에서 오래 걸리는 로직(슬로우 쿼리, 외부 API 호출 등)이 있으면, 커넥션을 장시간 점유하게 된다. 이렇게 되면
커넥션을 회수하지 못하고 대기열만 쌓임 → 고갈 상태가 된다.
3. 예상 외 트래픽 폭주
대규모 이벤트, 외부 봇 공격, 잘못된 반복 호출 등으로 서버가 과도하게 많은 요청을 동시에 처리하게 되면, 커넥션 풀 한계를 초과할 수 있다.
4. 커넥션 풀 설정 오류
- maximumPoolSize를 너무 작게 설정
- connectionTimeout을 너무 짧거나 길게 잡은경우
위와 같은 설정 문제도 고갈을 부추길 수 있다.
고갈 대응 방법
방법 | 설명 |
커넥션 풀 크기 조정 | CPU 코어 수 x 2 또는 예상 TPS에 맞춰 조정 |
커넥션 타임아웃 설정 | connectionTimeout을 적절하게 조절(ex: 5초) |
커넥션 반납 철저 관리 | close 누락 방지(try-with-resources 적극 사용) |
트랜잭션 최소화 | DB 점유 시간을 줄인다(슬로우 쿼리 개선) |
커넥션 풀 모니터링 | HikariCP Metrics, JMX를 통해 실시간 감지 |
슬로우 쿼리 탐지 및 개선 | DB 쿼리 튜닝, 인덱스 최적화 |
백프레셔(Backpressure) 적용 | 서버에 요청이 몰릴 때, 내부적으로 대기시키거나 제한 |
이중화 및 읽기 전용 Replica DB 활용 | 부하 분산 |