프로그래밍 PROGRAMMING/자바 JAVA AND FRAMEWORKS

HikariCP 커넥션 풀 최적화 설정법

매운할라피뇨 2026. 3. 14. 09:40
반응형
HikariCP 커넥션 풀 최적화 설정법

HikariCP는 Spring Boot의 기본 커넥션 풀 라이브러리로, 낮은 지연 시간과 높은 처리량으로 널리 사용됩니다. 그러나 기본 설정만으로 운영 환경에 배포하면 커넥션 고갈, 응답 지연, 타임아웃 오류가 반복적으로 발생할 수 있습니다. 이 글에서는 HikariCP의 핵심 파라미터를 이해하고, 실제 프로젝트에 적용 가능한 커넥션 풀 최적화 전략을 다룹니다.


HikariCP 주요 설정 파라미터 이해

커넥션 풀 최적화의 첫 걸음은 각 파라미터가 무엇을 제어하는지 정확히 파악하는 것입니다. 잘못된 값 하나가 전체 서비스의 DB 연결을 차단할 수 있습니다.

파라미터 기본값 설명
maximumPoolSize 10 풀에서 유지할 최대 커넥션 수
minimumIdle maximumPoolSize 최소 유휴 커넥션 수
connectionTimeout 30,000ms 커넥션 획득 대기 최대 시간
idleTimeout 600,000ms 유휴 커넥션 유지 최대 시간
maxLifetime 1,800,000ms 커넥션 최대 수명
keepaliveTime 0 (비활성) DB 방화벽 타임아웃 방지용 ping 주기

maximumPoolSize를 무조건 높이는 것은 오히려 컨텍스트 스위칭 비용을 증가시킵니다. HikariCP 공식 문서는 pool size = (core_count * 2) + effective_spindle_count 공식을 권장하며, 일반적인 웹 애플리케이션에서는 10~20 범위가 적절합니다.


변경전 / 변경후 설정 비교

기본 설정을 그대로 사용하는 경우와 최적화된 설정을 비교합니다.
변경전 — Spring Boot 기본값에 의존하는 설정:

# application.yml (기본값 의존 — 문제 발생 가능)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb
    username: user
    password: secret
    driver-class-name: com.mysql.cj.jdbc.Driver

이 상태에서는 maximumPoolSize=10, connectionTimeout=30s가 적용되며, 트래픽 급증 시 커넥션 대기 큐가 금방 포화됩니다.

변경후 — 운영 환경을 고려한 최적화 설정:

# application.yml (최적화 설정)
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mydb?rewriteBatchedStatements=true&useSSL=false
    username: user
    password: secret
    driver-class-name: com.mysql.cj.jdbc.Driver
    hikari:
      maximum-pool-size: 20          # CPU(8코어) 기준: 8*2+4=20
      minimum-idle: 5                # 유휴 커넥션 최소 유지 (빠른 응답)
      connection-timeout: 5000       # 5초 초과 시 즉시 예외 (30초 대기 방지)
      idle-timeout: 300000           # 5분 유휴 후 커넥션 회수
      max-lifetime: 1200000          # 20분 — DB 방화벽 타임아웃보다 짧게 설정
      keepalive-time: 60000          # 1분마다 ping으로 좀비 커넥션 방지
      pool-name: MainHikariPool      # 모니터링 시 풀 식별
      connection-test-query: SELECT 1 # JDBC4 미지원 드라이버용 (MySQL 8+ 불필요)

핵심 포인트: max-lifetime은 반드시 DB 서버 또는 방화벽의 wait_timeout보다 짧게 설정해야 합니다. MySQL의 기본 wait_timeout은 28,800초(8시간)이지만, 클라우드 환경(AWS RDS, GCP Cloud SQL)에서는 더 짧게 설정된 경우가 많습니다.


Java Config로 다중 DataSource 관리

여러 DB를 사용하는 서비스에서는 application.yml보다 Java Config로 각 풀을 명시적으로 관리하는 것이 유지보수에 유리합니다.

@Configuration
public class DataSourceConfig {

    // Primary DB — 트래픽 집중, 풀 크기 크게
    @Bean
    @Primary
    public DataSource primaryDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://primary-db:3306/main");
        config.setUsername("user");
        config.setPassword("secret");
        config.setMaximumPoolSize(20);
        config.setMinimumIdle(5);
        config.setConnectionTimeout(5_000);      // 5초
        config.setMaxLifetime(1_200_000);         // 20분
        config.setKeepaliveTime(60_000);          // 1분
        config.setPoolName("PrimaryPool");
        return new HikariDataSource(config);
    }

    // Read Replica — 읽기 전용, 풀 크기 중간
    @Bean
    public DataSource readReplicaDataSource() {
        HikariConfig config = new HikariConfig();
        config.setJdbcUrl("jdbc:mysql://replica-db:3306/main");
        config.setUsername("reader");
        config.setPassword("secret");
        config.setMaximumPoolSize(10);
        config.setMinimumIdle(3);
        config.setConnectionTimeout(3_000);
        config.setMaxLifetime(1_200_000);
        config.setReadOnly(true);                 // 읽기 전용 명시
        config.setPoolName("ReplicaPool");
        return new HikariDataSource(config);
    }
}

HikariCP 모니터링 — 풀 상태 실시간 확인

설정 후에는 실제 풀이 예상대로 동작하는지 모니터링해야 합니다. Spring Boot Actuator와 Micrometer를 조합하면 Prometheus + Grafana 대시보드에서 커넥션 풀 지표를 실시간으로 확인할 수 있습니다.

build.gradle에 의존성을 추가합니다:

// build.gradle
dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-actuator'
    implementation 'io.micrometer:micrometer-registry-prometheus'
}

application.yml에서 메트릭 노출을 활성화합니다:

management:
  endpoints:
    web:
      exposure:
        include: health, metrics, prometheus
  metrics:
    tags:
      application: ${spring.application.name}

이후 /actuator/metrics/hikaricp.connections.active 엔드포인트에서 아래와 같은 응답을 확인할 수 있습니다:

{
  "name": "hikaricp.connections.active",
  "measurements": [
    { "statistic": "VALUE", "value": 4.0 }
  ],
  "availableTags": [
    { "tag": "pool", "values": ["MainHikariPool"] }
  ]
}

주목해야 할 주요 메트릭은 다음과 같습니다:

  • hikaricp.connections.active: 현재 사용 중인 커넥션 수
  • hikaricp.connections.pending: 커넥션 대기 중인 스레드 수 — 이 값이 지속적으로 0 이상이면 풀 부족 신호
  • hikaricp.connections.timeout: 타임아웃 발생 횟수 — 증가 추세라면 connectionTimeout 또는 maximumPoolSize 조정 필요

맺음말

HikariCP 커넥션 풀 최적화는 단순히 maximumPoolSize를 늘리는 작업이 아닙니다. 서버 코어 수, DB 서버 스펙, 방화벽 타임아웃, 애플리케이션 쿼리 패턴을 종합적으로 고려해야 적절한 값을 도출할 수 있습니다.

핵심 원칙을 정리하면 다음과 같습니다:

  1. max-lifetime은 반드시 DB wait_timeout보다 짧게 설정
  2. connectionTimeout은 30초가 아닌 3~5초로 줄여 빠른 장애 감지 유도
  3. keepaliveTime으로 클라우드 환경의 좀비 커넥션 사전 차단
  4. Micrometer 메트릭으로 pending 커넥션을 지속 모니터링

커넥션 풀 설정은 초기에 맞춰 놓고 잊어버리는 것이 아니라, 트래픽 패턴 변화에 따라 주기적으로 재검토해야 합니다. HikariCP 공식 문서의 "About Pool Sizing" 섹션도 함께 참고하면 이론적 배경을 더 깊이 이해하는 데 도움이 됩니다.

반응형