Junglog.
DB

HikariCP

HikariCP 특징과 장점

최정환·2025년 3월 6일·6분 읽기143 views

HikariCP를 장애 이후 다시 이해해보기

이 글은 운영 환경에서 DB 커넥션 끊김 문제를 겪은 뒤, HikariCP를 단순한 “빠른 커넥션 풀”이 아니라 애플리케이션과 DB 사이의 안정성을 관리하는 구성 요소로 다시 이해하게 된 내용을 정리한 글입니다.

Spring Boot 기반 애플리케이션을 개발하다 보면 대부분 자연스럽게 HikariCP를 사용하게 됩니다.

별도로 커넥션 풀을 설정하지 않아도 기본 커넥션 풀로 HikariCP가 사용되기 때문에, 처음에는 단순히 “빠른 JDBC Connection Pool” 정도로만 이해하고 넘어가기 쉽습니다.

하지만 운영 환경에서 DB 커넥션 장애를 겪고 나면 HikariCP는 단순한 성능 최적화 도구가 아니라는 것을 알게 됩니다.

특히 다음과 같은 상황에서는 커넥션 풀이 어떻게 동작하는지 이해하는 것이 중요합니다.

  • DB 커넥션이 간헐적으로 끊기는 경우
  • 방화벽이나 네트워크 장비가 idle connection을 종료하는 경우
  • 죽은 커넥션을 애플리케이션이 다시 사용하려는 경우
  • Connection is not available 오류가 발생하는 경우
  • 트래픽 증가로 커넥션 풀이 부족해지는 경우

HikariCP란?

HikariCP는 JDBC Connection Pool 라이브러리입니다.

DB 요청이 들어올 때마다 새로운 커넥션을 만들고 종료하면 비용이 큽니다.
그래서 애플리케이션은 미리 여러 개의 DB 커넥션을 만들어두고, 요청이 들어올 때마다 풀에서 커넥션을 빌려 사용한 뒤 다시 반환합니다.

즉, HikariCP의 역할은 단순히 커넥션을 빠르게 만드는 것이 아닙니다.

  • DB 커넥션을 미리 생성해 재사용하고
  • 동시에 사용할 수 있는 커넥션 수를 제한하며
  • 비정상 커넥션을 감지하고 제거하고
  • 애플리케이션과 DB 사이의 부하를 조절합니다.


HikariCP가 빠르다는 것은 무슨 의미일까?

HikariCP를 설명할 때 자주 나오는 표현이 있습니다.

빠르고 가벼운 JDBC 커넥션 풀

틀린 말은 아니지만, 이 표현만으로는 부족합니다.

HikariCP가 빠르다는 것은 커넥션을 빌리고 반환하는 과정에서 불필요한 오버헤드를 줄였다는 의미에 가깝습니다.

커넥션 풀은 멀티스레드 환경에서 동작합니다.
여러 요청이 동시에 커넥션을 가져가고, 사용이 끝나면 다시 반환합니다.

이 과정에서 동기화 비용이 크거나, 객체 생성이 많거나, 내부 구조가 복잡하면 커넥션 풀 자체가 병목이 될 수 있습니다.

HikariCP는 이런 비용을 줄이기 위해 내부 구조를 단순하고 가볍게 가져갑니다.

정리하면 핵심은 이것입니다.

적은 오버헤드로 커넥션을 빠르게 빌려주고, 사용이 끝난 커넥션을 빠르게 회수한다.

그래서 HikariCP를 볼 때 단순히 “빠르다”보다, 커넥션 획득과 반환 비용을 줄인 커넥션 풀이라고 이해하는 편이 더 좋습니다.

운영 장애에서 중요한 것은 죽은 커넥션이다

운영 환경에서 문제가 되는 경우는 보통 “커넥션을 얼마나 빠르게 빌리느냐”보다 “풀 안의 커넥션이 정말 살아있느냐”입니다.

커넥션 풀 안에 있는 커넥션은 항상 정상이라고 보장할 수 없습니다.

예를 들어 다음과 같은 상황이 생길 수 있습니다.

  • DB 서버가 커넥션을 종료함
  • 방화벽이 오래된 idle connection을 끊음
  • 네트워크 장비가 유휴 TCP 연결을 제거함
  • DB 재기동으로 기존 커넥션이 무효화됨
  • 애플리케이션은 끊긴 줄 모르고 기존 커넥션을 재사용함

이때 애플리케이션이 죽은 커넥션을 그대로 사용하면 쿼리 실행 시점에 오류가 발생합니다.

즉, HikariCP에서 중요한 것은 단순히 커넥션을 많이 만들어두는 것이 아니라, 정상적인 커넥션만 풀에 유지하는 것입니다.

HikariCP는 SELECT 1만 사용하는 구조가 아니다

기존에 내가 잘못 이해했던 부분 중 하나는 Connection Validation이었습니다.

처음에는 HikariCP가 커넥션을 검증할 때 단순히 SELECT 1 같은 쿼리를 날린다고 생각하기 쉽습니다.

하지만 HikariCP는 JDBC4를 지원하는 드라이버에서는 기본적으로 Connection.isValid()를 사용합니다.

connectionTestQuery는 JDBC4를 지원하지 않는 레거시 드라이버에서 사용하는 대체 수단에 가깝습니다.

즉, 다음과 같이 이해하는 것이 더 정확합니다.

text
기본 방식: JDBC4 Connection.isValid()
대체 방식: connectionTestQuery

그래서 특별한 이유 없이 아래 설정을 무조건 넣는 것은 권장되지 않습니다.

properties
spring.datasource.hikari.connection-test-query=SELECT 1

드라이버가 JDBC4를 지원한다면 HikariCP의 기본 검증 방식을 그대로 사용하는 것이 좋습니다.

keepaliveTime은 무엇을 해결할까?

운영 환경에서 방화벽이나 네트워크 장비가 idle connection을 끊는 경우가 있습니다.

문제는 애플리케이션 입장에서는 이 커넥션이 끊겼는지 바로 알기 어렵다는 점입니다.

풀 안에는 커넥션 객체가 남아있지만, 실제 네트워크 연결은 이미 끊긴 상태일 수 있습니다.

이런 상황에서 keepaliveTime이 도움이 될 수 있습니다.

keepaliveTime은 idle 상태의 커넥션을 주기적으로 꺼내 살아있는지 확인한 뒤 다시 풀에 반환합니다.

여기서 중요한 점은 keepaliveTime이 모든 커넥션에 계속 ping을 보내는 설정이 아니라는 것입니다.

HikariCP의 keepalive는 idle connection에 대해서만 동작합니다.

검증 과정에서 죽은 커넥션으로 판단되면 HikariCP는 해당 커넥션을 제거하고 새 커넥션을 생성합니다.

설정값보다 중요한 것

HikariCP를 공부하다 보면 자연스럽게 여러 설정값을 보게 됩니다.

  • maximumPoolSize
  • minimumIdle
  • connectionTimeout
  • validationTimeout
  • idleTimeout
  • keepaliveTime
  • maxLifetime
  • leakDetectionThreshold

하지만 이 글에서 각 설정의 정의를 길게 정리하지는 않으려고 합니다.
설정값 자체는 공식 문서를 보면 더 정확하게 확인할 수 있기 때문입니다.

운영에서 더 중요한 것은 “각 속성이 무엇인지”보다 왜 이 값을 조정해야 하는지입니다.

예를 들어 connectionTimeout을 짧게 설정하면 장애를 빠르게 감지할 수 있습니다.
하지만 너무 짧으면 순간적인 지연도 장애로 판단할 수 있습니다.

반대로 너무 길게 설정하면 실제 장애 상황에서 요청 스레드가 오래 묶일 수 있습니다.

maxLifetime도 마찬가지입니다.
DB나 방화벽이 먼저 커넥션을 끊기 전에 HikariCP가 커넥션을 교체하도록 맞추는 것이 중요합니다.

즉, 설정값은 정답이 있는 것이 아니라 환경에 맞춰 조정해야 합니다.

HikariCP 설정은 무엇과 함께 봐야 할까?

HikariCP 설정은 애플리케이션 내부만 보고 정할 수 없습니다.

다음 요소를 함께 봐야 합니다.

  • DB의 최대 커넥션 수
  • 애플리케이션 서버 인스턴스 수
  • 방화벽/NAT/LB의 idle timeout
  • 쿼리 평균 수행 시간
  • 피크 시간대 요청량
  • 트랜잭션 유지 시간
  • 커넥션 누수 여부

예를 들어 애플리케이션 서버가 4대이고 각 서버의 maximumPoolSize가 50이라면, 전체 애플리케이션이 DB에 만들 수 있는 커넥션은 최대 200개입니다.

text
앱 서버 4대 × maximumPoolSize 50 = 최대 DB 커넥션 200개

단일 서버 기준으로는 적당해 보여도, 전체 서버 기준으로 보면 DB에 부담이 될 수 있습니다.

그래서 커넥션 풀 설정은 항상 전체 시스템 관점에서 봐야 합니다.

장애를 겪고 난 뒤의 관점

장애를 겪기 전에는 HikariCP를 단순히 Spring Boot가 기본으로 사용하는 커넥션 풀 정도로만 생각했습니다.

하지만 운영 환경에서는 HikariCP가 애플리케이션과 DB 사이에서 중요한 완충 역할을 합니다.

커넥션을 무작정 많이 만드는 것이 아니라, 제한된 커넥션을 효율적으로 재사용해야 합니다.

또한 죽은 커넥션을 계속 들고 있지 않도록 검증하고, DB나 네트워크 장비의 timeout 정책보다 먼저 커넥션을 정리할 수 있어야 합니다.

결국 HikariCP 설정은 다음 두 가지 사이의 균형입니다.

text
빠르게 실패할 것인가?
안정적으로 기다릴 것인가?

장애를 빨리 감지하려면 timeout을 짧게 가져가야 하지만, 너무 짧으면 정상 요청도 실패할 수 있습니다.

반대로 안정적으로 기다리려면 timeout을 길게 가져갈 수 있지만, 실제 장애 상황에서는 요청 스레드가 오래 묶일 수 있습니다.

결론

HikariCP는 단순히 빠른 JDBC 커넥션 풀이 아닙니다.

운영 환경에서는 애플리케이션과 DB 사이의 커넥션을 안정적으로 관리하고, 죽은 커넥션을 감지하며, 과도한 DB 연결을 제한하는 중요한 역할을 합니다.

이번에 정리하면서 가장 중요하게 느낀 점은 다음과 같습니다.

  • HikariCP는 커넥션을 미리 생성하고 재사용한다.
  • 빠르다는 것은 커넥션 획득과 반환 오버헤드가 낮다는 의미다.
  • 커넥션 풀 안의 커넥션이 항상 살아있다고 볼 수는 없다.
  • 기본 검증은 JDBC4 Connection.isValid()를 사용한다.
  • connectionTestQuery는 레거시 드라이버를 위한 대체 수단에 가깝다.
  • keepaliveTime은 idle connection을 주기적으로 검증한다.
  • 커넥션 풀 설정은 DB, 네트워크 장비, 트래픽 패턴과 함께 봐야 한다.

결국 HikariCP를 제대로 이해한다는 것은 속성값을 많이 외우는 것이 아니라, 애플리케이션과 DB 사이에서 커넥션이 어떤 생명주기를 가지는지 이해하는 것에 가깝습니다.