Java에서 connection pool이 exhausted 되면, 원인은 slow query, leaked connection, 긴 transaction hold time, 혹은 현재 운영 압박과 맞지 않는 pool 가정일 수 있습니다.
그래서 “pool이 바닥났다”는 말만으로는 아직 진단이 아닙니다. 어떤 경우에는 pool이 작고, 어떤 경우에는 connection이 너무 늦게 돌아오며, 어떤 경우에는 애초에 query나 transaction이 너무 오래 점유합니다. 겉으로는 비슷하지만 해결 방향은 완전히 다릅니다.
이 글은 실전 순서에 집중합니다.
- connection leak과 긴 hold time을 어떻게 구분할지
- waiter가 쌓일 때 무엇을 먼저 볼지
- query latency, transaction scope, 트래픽 증가가 어떻게 exhaustion으로 이어지는지
짧게 말하면 active, idle, waiting 압박을 먼저 보고, connection hold time과 query time을 비교한 뒤, main issue가 leak인지, 느린 작업인지, pool sizing 가정 붕괴인지 판단해야 합니다.
더 넓은 Java 분기부터 다시 보고 싶다면 Java 트러블슈팅 가이드로 가세요.
pool size보다 hold time부터 보기
connection pool 사고는 단순히 pool이 작아서보다, connection이 너무 오래 점유되기 때문에 생기는 경우가 많습니다.
그래서 아래 질문이 먼저 중요합니다.
- 각 connection은 얼마나 오래 빌려져 있는가
- query는 실제로 얼마나 오래 도는가
- waiting thread는 얼마나 쌓이는가
이 분기 없이 보면 pool size부터 키우다가, 왜 pool이 바쁜지라는 핵심 질문을 놓치기 쉽습니다.
leak, slow work, waiter buildup은 같은 문제가 아니다
아래 패턴은 모두 겉으로 비슷한 증상을 만듭니다.
- borrow call이 대기하기 시작함
- latency가 급격히 오름
- thread pool이 뒤에서 쌓임
- timeout이 늘어남
하지만 같은 운영 문제는 아닙니다.
- 느린 query가 connection을 오래 점유함
- leak 때문에 connection이 돌아오지 않음
- 긴 transaction이 DB 밖 작업까지 connection을 붙잡음
- 트래픽 증가가 오래된 pool 가정을 넘어섬
더 유용한 질문은 “pool이 exhausted인가?”보다 “왜 waiter가 늘어나는가?”입니다.
자주 나오는 원인
1. 느린 query 또는 blocked transaction
connection이 오래 바쁘게 남아 있고, 부하가 올라가면 가용 수가 빠르게 줄어듭니다.
자주 보이는 단서는 아래와 같습니다.
- query latency가 먼저 상승함
- active connection이 limit 근처에 오래 머묾
- 느린 query path가 지배적이 된 뒤 waiting thread가 늘어남
이 branch에서는 pool 증상은 분명하지만, 더 깊은 문제는 query 속도나 transaction 동작입니다.
2. connection leak
빌린 connection이 정상적으로 반환되지 않을 수 있습니다.
이 패턴은 보통 아래에서 자주 나옵니다.
- exception path에서 close가 빠짐
- helper abstraction이 ownership을 흐림
- 장수 코드 경로가 빌린 자원을 돌려주지 않음
이 경우 pool은 단순히 바쁜 것이 아니라 시간이 갈수록 회복되지 않는 방향으로 나빠집니다.
3. concurrency 증가로 인한 waiter buildup
같은 pool을 기다리는 thread가 많아지면서 지연이 빠르게 커집니다.
자주 보이는 경우는:
- 요청 동시성이 커짐
- batch job이 live traffic과 같이 돌기 시작함
- retry가 같은 DB 경로 부하를 키움
- worker / executor 설정이 concurrency shape를 바꿈
이 경우 pool sizing이 중요할 수는 있지만, leak과 긴 hold time이 더 깊은 원인이 아닌지 먼저 봐야 합니다.
실전 점검 순서
connection pool이 바닥날 때는 아래 순서가 가장 도움이 됩니다.
- active, idle, waiting thread 확인
- connection hold time과 query latency 비교
- unclosed connection과 cleanup path 확인
- pool 압박과 트래픽 / concurrency 증가 비교
- leak인지, slow work인지, pool mismatch인지 판단
이 순서가 중요한 이유는 두 가지 흔한 실수를 막기 때문입니다.
- exhausted pool을 전부 sizing 문제처럼 보는 실수
- cleanup과 ownership을 보기 전에 slow query부터 단정하는 실수
DB보다 backlog가 더 눈에 띄면 Java thread pool queue가 계속 쌓일 때와 같이 보세요.
아주 작은 예시가 보여주는 핵심
HikariDataSource ds = new HikariDataSource();
ds.setMaximumPoolSize(10);
transaction이나 느린 query가 connection을 오래 잡고 있으면 borrow call이 pool limit 뒤에 빠르게 쌓이기 시작합니다.
여기서 중요한 것은 limit 수치가 아니라, 각 connection이 얼마나 오래 unavailable 상태로 남는가입니다.
DB 경로마다 물어볼 질문
각 요청이나 job 경로마다 아래를 물어보면 도움이 됩니다.
- connection은 언제 빌려오는가
- 잡고 있는 동안 무슨 작업을 하는가
- 언제 반드시 반환되는가
- exception path에서도 반환되는가
이 프레이밍이 좋은 이유는 connection pool 장애가 capacity 문제처럼 보여도 실제로는 lifecycle과 ownership 문제인 경우가 많기 때문입니다.
FAQ
Q. pool exhaustion이면 항상 DB가 느린 건가요?
아닙니다. connection leak, 긴 transaction hold time, concurrency 증가 때문에도 같은 증상이 날 수 있습니다.
Q. 무엇부터 보는 게 가장 빠른가요?
active, idle, waiting 압박을 먼저 보고, connection hold time과 query latency를 비교하세요.
Q. pool size를 키우면 충분한가요?
도움이 될 때도 있지만, 더 깊은 원인이 connection lifetime, cleanup failure, blocked transaction이라면 첫 해결책으로는 적절하지 않습니다.
Read Next
- Java 전체 분기부터 다시 보고 싶다면 Java 트러블슈팅 가이드로 가세요.
- DB보다 backlog가 더 눈에 띄면 Java thread pool queue가 계속 쌓일 때를 보세요.
- memory 압박도 함께 보이면 Java OutOfMemoryError도 같이 보세요.
Related Posts
Sources:
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.
먼저 읽어볼 가이드
검색 유입이 많은 핵심 글부터 이어서 보세요.
- 미들웨어 트러블슈팅 가이드: Redis vs RabbitMQ vs Kafka 개발자를 위한 미들웨어 트러블슈팅 허브 글입니다. Redis, RabbitMQ, Kafka 중 어떤 증상부터 먼저 봐야 하는지와 어떤 문제 패턴이 각 시스템에 가까운지 정리합니다.
- Kubernetes CrashLoopBackOff: 먼저 볼 것들 startup failure, probe, config, resource limit 관점에서 CrashLoopBackOff를 어떻게 나눠서 봐야 하는지 정리한 가이드입니다.
- Kafka consumer lag가 계속 늘 때: 트러블슈팅 가이드 Kafka consumer lag가 계속 늘어날 때 무엇부터 봐야 하는지 정리합니다. poll 주기, 처리 속도, rebalance, consumer 설정까지 실전 기준으로 다룹니다.
- Kafka Rebalancing Too Often 가이드 Kafka consumer group에서 rebalance가 너무 자주 일어날 때 membership flapping, poll timing, protocol, assignment churn을 어떤 순서로 봐야 하는지 설명하는 실전 가이드입니다.
- Docker container가 계속 재시작될 때: 먼저 확인할 것들 exit code, command failure, environment mistake, health check 관점에서 Docker restart loop를 푸는 실전 가이드입니다.
심사 대기 중에는 광고 대신 관련 가이드를 먼저 보여줍니다.