스프링 개발자/DB

커넥션 풀의 변천사[old vs modern]

르무엘 2026. 1. 2. 10:15

과거에 주로 사용되던 Commons DBCPC3P0 같은 "옛날 스타일"의 커넥션 풀과 현재 표준인 HikariCP는 설계 철학부터 성능 최적화 방식까지 큰 차이가 있습니다.

단순히 "더 빠르다"를 넘어, 어떤 기술적 포인트가 다른지 비교해 정리해 드립니다.


1. 한눈에 보는 비교 (Old vs. Modern)

구분 옛날 스타일 (DBCP, C3P0) 요즘 스타일 (HikariCP)
철학 풍부한 기능과 세밀한 옵션 제공 극단적인 단순화와 성능 최적화
라이브러리 크기 상대적으로 무거움 (수 MB) 매우 가벼움 (약 130KB)
동기화 전략 synchronized 등 무거운 락 위주 Lock-free 설계 (ConcurrentBag)
연결 검증 testOnBorrow, validationQuery 위주 maxLifetime 기반의 선제적 교체
바이트코드 표준 JDK Proxy 사용 Javassist를 이용한 바이트코드 최적화

2. 결정적인 기술적 차이점

① 연결 관리의 패러다임: "검사" vs "교체"

  • 옛날 방식: "이 커넥션 아직 살아있나?"라고 끊임없이 DB에 물어봅니다 (test-while-idle, testOnBorrow). 이 과정 자체가 DB 부하가 되고 응답 속도를 늦춥니다.
  • HikariCP 방식: 커넥션의 **유효 수명(maxLifetime)**을 정해두고, 시간이 다 되면 조용히 폐기하고 새것으로 바꿉니다. 굳이 살아있는지 찔러보지 않아도 신선한 상태를 유지하는 전략입니다.

② 동기화 구조: ConcurrentBag

옛날 풀들은 여러 스레드가 동시에 커넥션을 요청하면 줄을 세우기 위해 무거운 락(Lock)을 걸었습니다. 반면, HikariCP는 ConcurrentBag이라는 특수한 구조를 사용합니다.

  • ThreadLocal 캐싱: 내가 썼던 커넥션을 우선적으로 다시 찾게 해줍니다.
  • Queue-stealing: 내 주머니에 없으면 다른 스레드의 주머니에서 남는 걸 가로채 옵니다. 이 과정에서 락 경합을 최소화하여 성능을 폭발적으로 끌어올렸습니다.

③ 바이트코드 수준의 다이어트

HikariCP 개발자들은 CPU 캐시 적중률까지 고려했습니다. 코드를 극단적으로 줄여서 컴파일된 바이트코드가 CPU 캐시에 더 잘 올라가도록 설계했습니다. 심지어 Java의 표준 Proxy 객체가 무겁다고 판단해, Javassist라는 도구로 직접 최적화된 프록시를 생성해서 씁니다.


3. 설정 시 주의사항 (마이그레이션 팁)

과거 설정 방식에 익숙하다면 HikariCP를 쓸 때 당황할 수 있는 부분들입니다.

  • minimumIdle 설정 지양: 과거에는 커넥션을 미리 많이 만들어두는 게 미덕이었으나, HikariCP는 maximumPoolSize와 동일하게 맞추는 Fixed Pool 방식을 강력히 권장합니다. (풀 크기가 변하면 그 자체가 오버헤드이기 때문)
  • validationQuery 생략: 최신 JDBC 드라이버는 isValid() API를 지원하므로, SELECT 1 같은 쿼리를 직접 작성할 필요가 없습니다. HikariCP는 드라이버 수준에서 유효성을 체크합니다.
  • maxLifetime의 중요성: DB의 wait_timeout보다 최소 30초 이상 짧게 설정해야 "죽은 커넥션"을 잡는 불상사를 막을 수 있습니다.

 

LIST