Skip to the content.

MySQL HikariCP 설정 가이드

목적: Spring Boot 3.5.x + MySQL 8.0+ HikariCP Connection Pool 표준 설정


1️⃣ 핵심 원칙

HikariCP를 사용하는 이유

Spring Boot 기본 커넥션 풀:

성능 비교:


2️⃣ 필수 설정 5가지

1. Pool Size

spring:
  datasource:
    hikari:
      maximum-pool-size: 20  # 최대 커넥션 수
      minimum-idle: 10       # 최소 유휴 커넥션

HikariCP 공식 권장:

connections = ((core_count * 2) + effective_spindle_count)

환경별 권장 범위: | 환경 | Pool Size | 이유 | |——|———–|——| | Local | 5-10 | 단일 개발자 | | Dev | 10-20 | 팀 개발 | | Prod | 20-50 | CPU 기반 조정 |

주의사항:

-- MySQL max_connections 확인
SHOW VARIABLES LIKE 'max_connections';
-- 권장: 3개 인스턴스 * 20 = 60 < 151 (MySQL 기본값)

2. Connection Timeout

spring:
  datasource:
    hikari:
      connection-timeout: 30000  # 30초 (밀리초)

의미: 커넥션 풀에서 커넥션을 얻기 위한 최대 대기 시간

권장값: 30초 (30000ms)

기준:


3. Max Lifetime

spring:
  datasource:
    hikari:
      max-lifetime: 1800000  # 30분 (밀리초)

의미: 커넥션이 풀에서 유지되는 최대 시간

권장값: DB wait_timeout의 70-80%

계산 방법:

-- MySQL wait_timeout 확인
SHOW VARIABLES LIKE 'wait_timeout';
-- 기본값: 28800초 (8시간)

-- HikariCP max-lifetime 설정
-- 8시간 * 0.7 = 5.6시간 = 20160초 = 20160000ms

이유: DB가 커넥션을 닫기 전에 먼저 종료 (Dead Connection 방지)


4. Leak Detection

spring:
  datasource:
    hikari:
      leak-detection-threshold: 60000  # Prod: 60초, Local: 0

의미: 커넥션 누수 감지 시간 (반환하지 않은 경우)

환경별 설정:

누수 예방:

// ❌ 나쁜 예 - 커넥션 반환 안 함
Connection conn = dataSource.getConnection();
// conn.close() 호출 안 함!

// ✅ 좋은 예 - try-with-resources
try (Connection conn = dataSource.getConnection()) {
    // 작업 수행
}  // 자동 close()

5. OSIV 비활성화

spring:
  jpa:
    open-in-view: false  # ❌ 필수!

OSIV의 문제점:

대안 (Transaction 내 Fetch Join):

@Service
@Transactional(readOnly = true)
public class GetOrderWithUserService {
    @Override
    public OrderResponse execute(GetOrderQuery query) {
        // ✅ Transaction 내에서 Fetch Join
        Order order = loadOrderPort.loadWithUser(query.orderId());
        return OrderResponse.of(order);
    }
}

3️⃣ 환경별 설정 템플릿

Local 환경 (application-local.yml)

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring_standards?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=Asia/Seoul
    username: root
    password: ${DB_PASSWORD}

    hikari:
      # Pool Size
      maximum-pool-size: 10
      minimum-idle: 5

      # Timeout
      connection-timeout: 20000  # 20초
      idle-timeout: 300000  # 5분
      max-lifetime: 600000  # 10분

      # Leak Detection (비활성화)
      leak-detection-threshold: 0

      # Pool Name
      pool-name: HikariPool-Local

      # MySQL 최적화
      data-source-properties:
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048
        useServerPrepStmts: true
        rewriteBatchedStatements: true

  jpa:
    hibernate:
      ddl-auto: validate  # ✅ Flyway 사용 시 validate
    properties:
      hibernate:
        format_sql: true
        use_sql_comments: true
    show-sql: false  # ❌ Logback 사용

  flyway:
    enabled: true
    locations: classpath:db/migration

logging:
  level:
    com.ryuqq: DEBUG
    org.hibernate.SQL: DEBUG
    org.hibernate.orm.jdbc.bind: TRACE

Prod 환경 (application-prod.yml)

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME}?useSSL=true&requireSSL=true&serverTimezone=Asia/Seoul
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

    hikari:
      # Pool Size (CPU 기반 조정)
      maximum-pool-size: 20
      minimum-idle: 10

      # Timeout
      connection-timeout: 30000  # 30초
      idle-timeout: 600000  # 10분
      max-lifetime: 1800000  # 30분

      # Leak Detection (활성화)
      leak-detection-threshold: 60000  # 60초

      # Pool Name
      pool-name: HikariPool-Prod

      # Connection Init SQL
      connection-init-sql: SELECT 1

      # MySQL 최적화
      data-source-properties:
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048
        useServerPrepStmts: true
        rewriteBatchedStatements: true
        cacheResultSetMetadata: true
        cacheServerConfiguration: true
        elideSetAutoCommits: true
        maintainTimeStats: false

  jpa:
    hibernate:
      ddl-auto: validate  # ✅ Flyway 사용
    properties:
      hibernate:
        format_sql: false
        use_sql_comments: false
        jdbc:
          batch_size: 50
          fetch_size: 50
        order_inserts: true
        order_updates: true
        batch_versioned_data: true
        query:
          plan_cache_max_size: 2048
          in_clause_parameter_padding: true
    show-sql: false

  flyway:
    enabled: true
    locations: classpath:db/migration
    baseline-on-migrate: true

logging:
  level:
    com.ryuqq: INFO
    org.hibernate.SQL: WARN

4️⃣ JPA/Hibernate 최적화

1. DDL Auto 전략

spring:
  jpa:
    hibernate:
      ddl-auto: validate  # ✅ Flyway 사용 시 validate 필수

옵션 설명: | 옵션 | 동작 | 권장 환경 | |——|——|———–| | validate | 엔티티-테이블 검증만 | ✅ Flyway 사용 시 (권장) | | update | 스키마 자동 ALTER | ❌ 위험 (데이터 손실) | | create | 시작 시 DROP + CREATE | ❌ Prod 절대 금지 | | create-drop | 종료 시 DROP | ❌ 테스트 전용 |


2. Batch Processing

spring:
  jpa:
    properties:
      hibernate:
        jdbc:
          batch_size: 50
          fetch_size: 50
        order_inserts: true
        order_updates: true
        batch_versioned_data: true

효과:

// 50개 INSERT를 1번의 네트워크 라운드트립으로 처리
for (int i = 0; i < 1000; i++) {
    Order order = Order.create(customerId, orderItems, clock);
    orderRepository.save(order);
}
// Without Batch: 1000번 네트워크 왕복
// With Batch: 20번 네트워크 왕복 (50개씩)

3. Query Plan Cache

spring:
  jpa:
    properties:
      hibernate:
        query:
          plan_cache_max_size: 2048
          in_clause_parameter_padding: true

Query Plan Cache:

IN Clause Parameter Padding:

-- Without Padding
WHERE id IN (?, ?, ?)  -- 3개 (새 Plan)
WHERE id IN (?, ?, ?, ?, ?)  -- 5개 (새 Plan)

-- With Padding (2의 제곱수)
WHERE id IN (?, ?, ?, ?)  -- 4개 (2^2)
WHERE id IN (?, ?, ?, ?, ?, ?, ?, ?)  -- 8개 (2^3)

5️⃣ 모니터링 (Prod)

Actuator + Prometheus

# application-prod.yml
management:
  endpoints:
    web:
      exposure:
        include: health,metrics,prometheus
  metrics:
    export:
      prometheus:
        enabled: true

주요 메트릭:

Alert 기준:


6️⃣ 보안 설정

환경 변수 사용

spring:
  datasource:
    url: jdbc:mysql://${DB_HOST:localhost}:${DB_PORT:3306}/${DB_NAME}
    username: ${DB_USERNAME}
    password: ${DB_PASSWORD}

환경 변수 설정 (Docker Compose):

services:
  app:
    environment:
      DB_HOST: mysql-server
      DB_PORT: 3306
      DB_NAME: spring_standards
      DB_USERNAME: app_user
      DB_PASSWORD: ${DB_PASSWORD}  # .env 파일에서 로드

주의:


7️⃣ 체크리스트

필수 설정

최적화 설정

모니터링 (Prod)


8️⃣ 절대 금지 사항


9️⃣ 참고 문서

HikariCP

MySQL

Spring Boot

관련 문서


작성자: Development Team 최종 수정일: 2025-11-13 버전: 1.0.0