Skip to content
hello tis
Go back

[26.11.03] 학습: idle connection 유지 비용과 connection pool 크기 조정하기

minimumIdle=maximumPoolSize로 connection을 미리 보관하면 되는데, idle connection을 줄이는 이유가 궁금했습니다. Spring Boot 3.4.4, HikariCP 5.1.0과 로컬 MySQL에서 유지하는 자원과 축소 후 첫 부하의 생성 대기를 비교했습니다.

maximumPoolSize와 minimumIdle의 역할 구분하기

pool 상태는 다음 용어로 구분합니다.

HikariCP 5.1.0의 주요 설정은 다음과 같습니다. Spring Boot에서는 spring.datasource.hikari.* 아래에 maximum-pool-size, minimum-idle처럼 설정합니다. Spring Boot DataSource 설정, HikariCP 설정

속성기본값역할
maximumPoolSize10active connection과 idle connection을 합한 pool 크기의 상한
minimumIdlemaximumPoolSize와 같음pool이 확보하려는 idle connection 수의 목표 최솟값
idleTimeout600,000ms, 10분minimumIdle을 초과한 idle connection의 정리 기준 시간
connectionTimeout30,000ms, 30초application이 pool에서 connection을 얻기까지 기다릴 시간

minimumIdle을 생략하면 상한과 같은 fixed-size pool이 됩니다. 이 값은 보충 목표이므로, 상한까지 모두 active connection이면 idle connection은 0개가 될 수 있습니다.

minimumIdle=0도 매 요청마다 connection을 끊는 설정은 아닙니다. 반환한 connection은 재사용하며, minimumIdle < maximumPoolSize일 때 idleTimeout을 넘긴 초과 idle connection을 정리합니다. 보충과 정리 구현

idle connection을 줄여 회수하는 자원 확인하기

application의 Connection.close()는 connection을 pool에 반환합니다. 이후 초과 idle connection의 physical connection까지 닫혀야 DB session과 socket FD(file descriptor)가 해제됩니다. idle connection은 SQL을 실행하지 않아도 session 상태와 buffer, thread 자원, JDBC 객체를 유지합니다. MySQL connection 메모리

자원 차이는 다음 조건으로 비교했습니다.

connection 수와 메모리 변화 비교하기

idle connection을 100개에서 2개로 줄였다 다시 100개로 늘렸을 때 DB connection 수, socket FD, 계측 메모리, JVM Heap과 MySQL RSS 비교

CPU 절감 효과 확인하기

connection을 다시 늘렸을 때 CPU가 함께 증가하지 않아, 이번 관측에서는 idle connection 축소의 CPU 절감 효과를 확인하지 못했습니다.

idle connection 100개, 2개, 다시 100개에서 MySQL process와 JVM process의 평균 CPU 사용량과 연속 관측 범위 비교

idle connection 축소 후 첫 부하의 비용 비교하기

닫은 connection을 다시 만들 때는 TCP connection, 인증과 session 초기화가 필요하고, TLS를 사용하면 해당 설정 비용도 듭니다. 첫 부하에서는 이 생성 비용과 다른 요청이 반환한 connection을 기다리는 시간이 함께 발생할 수 있습니다.

표는 3회 실험에서 각각 구한 connection 획득 p95의 중앙값이며, 괄호는 회차별 p95의 최소~최대입니다. 전체 요청을 합친 p95는 아닙니다.

minimumIdle추가 지연 없음생성에 100ms 추가
0255.23ms (255.18~274.70)563.37ms (547.38~564.23)
2184.84ms (176.14~186.26)309.44ms (307.34~309.84)
기본값 1071.81ms (66.57~73.80)82.81ms (72.31~83.80)

HikariCP 5.1.0은 일반적인 pool 확장을 단일 생성 thread에서 처리하므로, 요청이 몰려도 상한까지 즉시 채워지지는 않습니다. connection 생성 구현

minimumIdle=0과 minimumIdle=10에서 시작한 pool의 total connection 수와 pending thread 수 비교

같은 생성 지연에서 connectionTimeout=250ms로 줄이자 minimumIdle=0은 3회 모두 획득 실패가 발생했고, 기본값 10은 모두 없었습니다. 이 timeout은 pool에서 connection을 얻는 제한이며 SQL이나 transaction의 제한 시간이 아닙니다. 상세 조건과 원자료는 experiments/hikari-idle-burst/에 남겼습니다.

결론: 필요한 상한을 정하고 fixed-size pool을 우선하기

실제 SQL과 전체 instance의 DB connection 예산으로 maximumPoolSize를 정하고, 평시에도 그 크기를 유지할 수 있다면 minimumIdle=maximumPoolSize를 우선하겠습니다. HikariCP도 급격한 부하 대응을 위해 이 구성을 권장합니다. minimumIdle 권장 설정

SQL 실행 중 DB CPU나 lock wait가 늘었다면 SQL 비용과 connection usage time(빌린 뒤 반환할 때까지의 시간)을 확인해야 합니다. minimumIdle을 높여 해결할 문제는 아닙니다. 이번 SLEEP SQL 실험으로 실제 서비스의 최적 상한을 정할 수는 없습니다.

실험과 pool 동작을 바탕으로 상황별 조정 방향을 정리했습니다. 요청 유형별 운영 성능을 측정한 결과는 아닙니다.

상황조정 방향검증할 조건
꾸준한 요청 또는 예고 없는 급증, 첫 응답 지연에 민감자원 예산 안에서 fixed-size pool 유지기동 직후와 피크 첫 부하의 획득 대기
피크에도 pool 상한이 필요 이상으로 큼minimumIdle과 maximumPoolSize를 함께 축소획득 대기와 SQL 지연이 목표 안에 드는지 확인
피크 상한은 필요하지만 긴 idle 시간의 보유 자원이 부담minimumIdle을 낮추고 idleTimeout 조정축소 후 첫 부하의 획득 시간과 timeout
정해진 시간에 배치 실행idle 구간에 축소한다면 시작 전에 connection 준비준비 시간과 온라인 요청을 포함한 connection 예산

minimumIdle을 낮춰도 모든 pool이 상한까지 늘어날 가능성은 남습니다. DB connection 예산에는 rolling deployment 중 함께 실행되는 instance와 다른 서비스도 포함해야 합니다. fixed-size pool도 maxLifetime에 따른 교체나 장애 후 재연결은 발생합니다.


Share this post:

Next Post
[26.11.02] 학습: 목표와 이유가 드러나도록 글 다듬기