본문 바로가기
개발관련

Spring Boot & HikariCP 튜닝

by 부발자 2020. 3. 15.

Spring Boot 2.0부터 HikariCP로 Default Connection Pool로 변경되었습니다.

아래 그림을 보면 바뀐 이유를 알수가 있다. (빠르다)

 

GitHub Page

https://github.com/brettwooldridge/HikariCP

 

 

 

 

Spring Boot 를 사용하면, Gradle or Maven에 별도로 설정할 필요는 없다. 

spring-boot-starter-data-jpa 에 dependency에 걸려 Default로 hikariCP가 설정된다.

 

application.yml에서 hikariCP datasource 설정을 해보겠다.

spring:
  datasource:
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://localhost:3306/db
    username: root
    password:
    hikari:
      poolName: Hikari
      maximum-pool-size: 10
      max-lifetime: 1800000
      auto-commit: false
      data-source-properties:
        cachePrepStmts: true
        prepStmtCacheSize: 250
        prepStmtCacheSqlLimit: 2048
        useServerPrepStmts: true

 

  • connection-timeout (Default : 30000) (30초)
  • 풀에서 connection을 얻을 때 최대 대기 시간을 설정한다.
    대기 시간안에 connection을 구하지 못하면 익셉션이 발생한다. 별도로 설정을 바꾸지 않아도 되기는 하지만, connection을 못 구한 트랙잭션을 실패를 허용하고, 빠르게 실패 났다고 응답을 하려면 더 짧게 변경해도 된다.

 

  • maximum-pool-size (Default : 10)
  • 유휴 상태와 사용 중인 커넥션을 포함해서 풀이 허용하는 최대 커넥션 개수를 설정한다.
    풀이 이 크기에 도달하고 유휴 커넥션이 없을 때 connectionTimeout이 지날 때까지 getConnection() 호출은 블록킹 된다.

    Connection is not available, request timed out after 30000ms
    간혹 위와 같은 에러 메시지가 나온다면 pool locking (deadlock) 상태에 빠진 상태이다. 기본적으로 connection timeout 30초인데, pool에서 connection을 30초 동안 획득하지 못한 상태로 이해하면 된다.

    발생 원인은 1개의 Transation에서 2개 이상의 connection을 사용할 때이다.  가령, maximum-pool-szie 가 10로 설정하고, 10개의 Transation에서 모두 1개의 connection 을 획득 한 상태에서 10개의 Transation에서 모두 1개 더 connection 을 대기하게 된다면, deadlock 상태가 된다. 간단히 해결하려면, maximum-pool-size 값을 늘려주면 되지만,  원천적인 원인은 애플리케이션 문제이다.

    pool sizing에 대해서 더 자세한 내용은 아래 링크를 참고하자
    https://github.com/brettwooldridge/HikariCP/wiki/About-Pool-Sizing

 

  • minimum-idle (Default : maximum-pool-size와 동일)
  • 풀에서 유지해줄 유휴 상태의 커넥션 최소 개수를 설정한다.
    최적의 성능과 응답성을 요구한다면 이 값은 설정하지 않는 게 좋다고 hikariCP github에 나와있다.

 

  • idle-timeout (Default : 600000) (10분)
  • 풀에서 유휴 상태로 유지시킬 최대 시간 시간을 설정한다.
    이 값은 minimum-idle 값이 maximum-pool-size 값보다 작은 경우에만 동작하도록 되어 있다.

 

  • max-lifetime (Default : 1800000) (30분)
  • 커넥션의 최대 유지 시간을 밀리초 단위로 설정한다.
    이 시간이 지난 커넥션 중에서 미사용 커넥션은 즉시 종료하고, 사용 중인 커넥션은 종료된 이후에 풀에서 제거한다.

    MySQL은 자신에게 맺어진 커넥션 중일정 시간 이상 사용하지 않은 커넥션을 종료 하는 프로세스가 존재합니다. (MySQL의 wait_timeout이라는 값을 통해 확인할 수 있고 default 8시간)

    기존 DBCP들은 연결을 맺은 커넥션들이 끊기는 것을 방지하기 위해 SELECT 1 등의 쿼리를 주기적으로 날려 이 문제를 회피하는 반면 HikariCP는 maxLifetime 설정값에 따라 스스로 커넥션을 유지하고, maxLifetime 이 지난 커넥션은 종료시키고 새로 커넥션을 생성하는 사이클이 반복되는 방식이다.

    HikariCP 개발자의 의도는 유휴 상태를 체크하는 쿼리 자체도 불필요한 리소스 낭비라 생각을 하고, 유휴 또는 수명 제한을 초과하여 폐기된 연결을 교체하는 데 드는 비용은 일반적으로 두 자릿수 밀리 초 단위로 측정되기 때문에 maxLifetime 개념을 뒀다고 한다.

    possibly consider using a shorter maxlifetime value
    간혹 위와 같은 오류가 나오게 된다면, maxlifetime 시간을 mysql의 wait_timeout 시간보다 2~3초 짧게 설정하면 된다.
    (mysql은 global, session wait_timeout으로 2개의 종류에 있음에 주의한다.)

 

  • auto-commit (Default : true)
  • 커넥션 풀의 auto commit 여부를 설정한다.

    Spring Boot 2부터 커넥션 풀의 auto-commit 설정값에 따라 hibernate.connection.provider_disables_autocommit: true를 자동으로 설정해준다. 이 값은 hibernate가 커넥션 풀의 autocommit 값을 따르겠다는 의미이다.
    hibernate 특성상 트랜젝션 시작 전 autoCommit 가 true 라면, autoCommit 값을 false로 설정하고, 트랜젝션이 끝나면 autoCommit 값을 원래 값으로 바꿔주는 로직이 존재한다.
    hikariCP의 auto-commit=false로 설정하고, hibernate의 provider_disables_autocommit 값을 true로 자동 설정 함으로써, hibernate의 불필요한 로직을 skip 함으로써 성능을 향상한다.
    만약 provider_disables_autocommit=true로 놓고 커넥션 풀의 autoCommit을 true로 놓게 되면 트랜젝션은 동작하지 않는다. 실패하더라도, 롤백이 되지 않으므로 주의하도록 하자

 

  • data-source-properties
  • 이 값은 hikariCP의 PreparedStatement caching을 설정하는 값들이다.
    위의 설정은 Mysql 접속 시 best practice 임으로 그대로 사용해도 무방하다. 아래 링크에서 보면 더 자세히 나와 있으므로 참고하도록 한다.
    https://github.com/brettwooldridge/HikariCP/wiki/MySQL-Configuration
반응형

'개발관련' 카테고리의 다른 글

MSA 분산 트랜잭션  (0) 2020.04.27
Optimistic Lock과 Pessimistic Lock  (0) 2020.04.15
Webflux vs WebMvc 성능 비교  (0) 2020.04.06
Spring Webflux Cold / Hot 이해하기  (0) 2020.03.29
Spring Webflux, 이해하고 사용하자  (0) 2020.03.21