우아한테크코스 레벨 4 팀 프로젝트 festabook에서 학습한 내용을 정리한 글입니다.
💭 들어가며
우리 서버의 TPS 측정을 진행하기 전에 커넥션 풀 설정을 검토하면서, JDBC 관점에서 커넥션과 커넥션 풀의 개념을 명확히 정리할 필요가 있었다. 레벨 4 JDBC 미션에서 제공된 수업 자료를 참고하여 학습했고, 이를 기반으로 정리한 내용이다.
✅ 커넥션(Connection)
커넥션(Connection)은 애플리케이션이 DB에 명령을 전달하고 결과를 수신하기 위해 생성되는 네트워크 기반 세션이다. 커넥션 생성 과정에서는 DB 소켓 연결(TCP Handshake), 사용자 인증, 세션 환경 설정 등이 수행되며, 이로 인해 생성과 종료 비용이 크다.

▶ 커넥션 생성 방법
🔽 DriverManager
Connection connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test", "user", "pw"
);
- 클래스 기반 접근 방식이다.
- 내부에 등록된 JDBC 드라이버 목록을 순회하여 알맞은 드라이버를 찾아 커넥션을 생성한다.
- DB 종류가 변경되면 코드 내 URL 및 드라이버 설정을 직접 수정해야 한다.
- 커넥션 풀링 및 분산 트랜잭션 환경을 지원하지 않는다.
🔽 DataSource
DataSource dataSource = new HikariDataSource();
dataSource.setURL("jdbc:mysql://localhost:3306/test");
dataSource.setUser("user");
dataSource.setPassword("pw");
Connection connection = dataSource.getConnection();
- 인터페이스 기반 접근 방식이다.
- DB 연결 정보를 코드 외부(Config)에서 주입할 수 있다.
- 커넥션 풀링 및 분산 트랜잭션 환경을 지원한다.
✅ 커넥션 풀(Connection Pool)

커넥션 풀(Connection Pool)은 커넥션 객체를 미리 생성해 두고 재사용하도록 관리하는 컨테이너이다. 이를 통해 커넥션 생성과 종료에 드는 비용을 줄일 수 있다. 대표적인 구현체로 HikariCP가 사용된다.
▶ HikariCP 설정
spring:
datasource:
hikari:
maximum-pool-size: 10 # 동시에 사용할 수 있는 커넥션의 최대 개수
minimum-idle: 10 # 풀에서 유지할 Idle(대기) 커넥션의 최소 개수
connection-timeout: 30000 # 커넥션 획득 대기 최대 시간(ms)
idle-timeout: 600000 # Idle 상태 커넥션이 유지될 수 있는 최대 시간(ms), 단 minimum-idle 이하로는 감소하지 않음
max-lifetime: 1800000 # 커넥션의 총 생존 가능 시간(ms), 초과 시 교체
pool-name: HikariPool-Simpsons # 커넥션 풀 이름
auto-commit: true # 커넥션 반환 시 자동 커밋 설정 여부
- maximum-pool-size: 동시에 사용 가능한 커넥션의 최대 개수이다. 이 값을 초과하면 요청은 대기 상태로 전환된다.
- minimum-idle: 요청이 없더라도 풀 내부에 유지할 Idle 커넥션의 최소 개수이다.
- connection-timeout: 커넥션을 획득하기 위해 대기할 수 있는 최대 시간(ms)이다. 초과 시 예외가 발생한다.
- idle-timeout: Idle 커넥션이 유지될 수 있는 최대 시간(ms)이다. 이 시간이 지나면 커넥션은 정리되고 삭제될 수 있다. 단, minimum-idle 이하로는 감소하지 않는다.
- max-lifetime: 커넥션이 풀 내에서 생존할 수 있는 최대 시간(ms)이다. 초과 시 커넥션이 폐기되고 새 커넥션으로 교체된다.
- pool-name: 커넥션 풀을 식별하기 위한 이름이다.
- auto-commit: 커넥션 반환 시 자동 커밋을 수행할지 여부이다. true이면 SQL 실행 후 자동으로 커밋된다.
이 외에도 다양한 설정 항목이 있으니 HikariCP 공식 문서를 참고한다.
🔽 참고
spring:
datasource:
hikari:
data-source-properties:
cachePrepStmts: true
prepStmtCacheSize: 250
prepStmtCacheSqlLimit: 2048
useServerPrepStmts: true
useLocalSessionState: true
rewriteBatchedStatements: true
cacheResultSetMetadata: true
cacheServerConfiguration: true
elideSetAutoCommits: true
maintainTimeStats: false
위 설정은 HikariCP 공식 문서에서 제시하는 MySQL 권장 설정이다.
▶ 이상적인 커넥션 풀 크기
🔽 코어 수 기반 공식
HikariCP 공식 문서에 따르면 커넥션 풀 크기는 다음과 같이 제시되어 있다.
connections = ((core_count * 2) + effective_spindle_count)
- 여기서 effective_spindle_count는 회전식 하드디스크(HDD)의 I/O 병렬 처리 단위를 의미한다.
- 해당 공식은 HDD 환경을 전제로 한 경험적 공식으로, SSD나 NVMe 환경에서는 유효성이 명확히 검증되지 않았다. 원문에서도 SSD 환경에 대한 적용은 권장되지 않음을 명시하고 있다.
🔽 Deadlock 회피를 위한 공식
HikariCP 공식 문서 및 관련 이슈에 따르면 Deadlock 회피 공식은 다음과 같이 제시되어 있다.
pool size = Tn x (Cm - 1) + 1
- Tn: 전체 Thread 개수
- Cm: 하나의 요청(Task)이 동시에 필요로 하는 커넥션 개수 (예: 동일 트랜잭션 내에서 추가 쿼리 수행 등)
해당 내용에 대한 상세 분석은 아래 글에서 잘 정리되어 있다.
- 우아한기술블로그 - HikariCP Dead lock에서 벗어나기 (이론편)
- 우아한기술블로그 - HikariCP Dead lock에서 벗어나기 (실전편)
🔽 정리(+ 개인적인 생각)
실제 환경에서는 CPU 코어 수 외에도 다양한 병목 요인이 존재한다. 동일한 서버에서 동일 조건으로 TPS 측정을 진행했을 때, 2코어 서버에서 커넥션 풀 크기를 4로 설정한 경우는 10으로 설정한 경우 대비 TPS가 절반 수준으로 감소하는 결과가 나타났다. 이는 병목 지점이 CPU가 아니라 네트워크 RTT, InnoDB 락 대기, fsync, 스토리지 지연 등 다른 요소에 의해 발생할 수 있음을 보여준다.
따라서 커넥션 풀 크기는 고정 공식으로 결정할 수 있는 값이 아니라, 실제 운영 환경에서 부하 테스트를 통해 적정 값을 도출하는 것이 필요하다.
📍 참고 자료
'Backend > Spring' 카테고리의 다른 글
| [Spring] Spring Security (2) | 2025.08.22 |
|---|---|
| [Spring] Spring, Spring Boot (0) | 2025.06.27 |
| [Spring] Spring MVC Config (0) | 2025.05.12 |
| [Spring] 스프링 빈(Spring Bean), Spring Core 어노테이션 (1) | 2025.04.23 |
| [Spring] IoC 컨테이너, 의존성 주입(DI) (2) | 2025.04.23 |