Spring Boot 서버의 Connection Pool 이해하기

코-드 텐카이·2025년 1월 5일

Spring Boot

목록 보기
3/10

스프링 부트로 서버를 개발하다 보면 데이터베이스 연결을 관리하는 Connection Pool을 자주 마주치게 됩니다. Thread Pool에 이어 Connection Pool에 대해 알아보겠습니다.

Connection Pool이란?

먼저 전체적인 개념을 이해해보겠습니다:

Pool 패턴의 개념과 장점

Pool 패턴은 비용이 많이 드는 리소스를 미리 생성해두고 재사용하는 디자인 패턴입니다.
이전 글에서 다룬 Thread Pool도 같은 패턴을 사용합니다:

  • Thread Pool: Thread 생성/삭제 비용 절감
  • Connection Pool: DB 연결 생성/삭제 비용 절감

Thread Pool과의 비교

Thread Pool과 Connection Pool은 비슷하면서도 다른 특징을 가집니다:

// Thread Pool 사용 예
@GetMapping("/users")
public List<User> getUsers() {
    // 1. Tomcat Thread Pool의 스레드가 요청을 처리
    return userRepository.findAll();  // 2. 이 때 Connection Pool에서 연결을 가져와 사용
}

주요 차이점:

  • Thread Pool: 요청 처리를 위한 작업 단위 관리
  • Connection Pool: 데이터베이스 연결이라는 특수 리소스 관리

DB Connection이 비싼 이유

새로운 데이터베이스 연결을 만드는 과정은 많은 비용이 듭니다:

  1. TCP 소켓 연결
  2. 데이터베이스 인증
  3. 세션 상태 초기화
  4. SSL/TLS 핸드쉐이크 (보안 연결 시)

이러한 과정을 매 요청마다 반복하면 성능이 크게 저하됩니다.

스프링 부트의 기본 Connection Pool: HikariCP

스프링 부트 2.0부터는 HikariCP가 기본 Connection Pool로 채택되었습니다.

HikariCP가 기본으로 채택된 이유

  1. 뛰어난 성능

    • 내부적으로 최적화된 메모리 사용
    • 락(lock) 경합 최소화
  2. 단순한 설정

    • 합리적인 기본값 제공
    • 직관적인 설정 방법

내부 구조

HikariCP의 주요 구성요소:

HikariDataSource
├── Connection Pool (ConcurrentBag)
│   ├── idle connections (사용 가능한 연결들)
│   └── in-use connections (사용 중인 연결들)
└── Connection Factory
    └── 새로운 연결 생성

기본 설정값들의 의미

HikariCP의 주요 설정값과 기본값:

spring:
  datasource:
    hikari:
      maximum-pool-size: 10
      minimum-idle: 10
      idle-timeout: 600000
      connection-timeout: 30000
      max-lifetime: 1800000

각 설정의 의미:

  • maximum-pool-size: 최대 연결 수
  • minimum-idle: 유휴 상태로 유지할 최소 연결 수
  • idle-timeout: 유휴 연결의 최대 유지 시간 (ms)
  • connection-timeout: 연결 대기 최대 시간 (ms)
  • max-lifetime: 연결의 최대 수명 (ms)

Connection Pool 설정하기

실제 서비스에 맞는 설정 방법을 알아보겠습니다.

application.yml에서의 설정 방법

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/mydb
    username: user
    password: pass
    hikari:
      maximum-pool-size: 50
      minimum-idle: 20
      idle-timeout: 300000  # 5분

권장되는 설정값과 그 이유

일반적인 권장사항:
1. CPU 코어 수를 고려
2. 데이터베이스 서버의 최대 연결 수 확인
3. 실제 부하 테스트로 검증

Connection Pool 상태 확인하기

개발 중에는 로그를 통해 Connection Pool의 상태를 확인할 수 있습니다:

spring:
  datasource:
    hikari:
      pool-name: "MyPool"     # 로그에서 구분하기 쉽게 풀 이름 지정
      leak-detection-threshold: 30000  # 커넥션 누수 감지 (30초)

logging:
  level:
    com.zaxxer.hikari.HikariConfig: DEBUG  
    com.zaxxer.hikari.pool.HikariPool: DEBUG

이렇게 설정하면 HikariCP의 동작 상태를 로그로 확인할 수 있습니다:

  • 커넥션 획득/반환
  • 풀 크기 변화
  • 커넥션 대기 시간

Thread Pool과의 관계

Thread Pool과 Connection Pool이 어떻게 함께 동작하는지 살펴보겠습니다.

Thread와 Connection의 관계

하나의 요청 처리 과정:

@Service
public class UserService {
    @Transactional
    public User createUser(UserDto dto) {
        // 1. Tomcat Thread Pool의 스레드가 이 메소드를 실행
        // 2. 트랜잭션 시작 - Connection Pool에서 연결 획득
        // 3. DB 작업 수행
        // 4. 트랜잭션 종료 - Connection Pool에 연결 반환
        return userRepository.save(new User(dto));
    }
}

Pool 크기 설정 시 고려사항

Thread Pool과 Connection Pool은 서로 균형이 중요합니다:

  1. Thread Pool이 Connection Pool보다 너무 클 때:

    • 많은 스레드가 적은 수의 커넥션을 기다림
    • 스레드들이 커넥션을 기다리며 대기 상태
    • 결과적으로 응답 지연 발생
  2. Connection Pool이 Thread Pool보다 너무 클 때:

    • 사용하지 않는 커넥션이 많아짐
    • 데이터베이스 서버의 리소스 낭비
    • 불필요한 메모리 사용

균형잡힌 설정의 예:

  • Thread Pool: 200개 (max threads)
  • Connection Pool: 50개 (maximum-pool-size)
    → 모든 스레드가 동시에 DB 작업을 하는 것이 아니므로, Connection Pool은 더 작게 설정

실제 요청이 처리되는 과정

일반적인 데이터베이스 요청 처리 흐름:

  1. 클라이언트 요청 도착
  2. Thread Pool에서 스레드 할당
  3. Connection Pool에서 연결 획득
  4. DB 작업 수행
  5. 연결 반환
  6. 스레드 반환

코드로 보면:

@GetMapping("/api/users/{id}")
public User getUser(@PathVariable Long id) {
    // Tomcat Thread Pool의 스레드
    try {
        // Connection Pool에서 연결 획득
        return userRepository.findById(id)
            .orElseThrow(() -> new NotFoundException());
    } finally {
        // Connection은 자동으로 Pool에 반환
    }
}

이렇게 설정한 Thread Pool과 Connection Pool은 서로 밀접하게 연관되어 동작하며,
두 Pool의 적절한 설정은 애플리케이션의 성능에 큰 영향을 미칩니다.


이상으로 스프링 부트 서버의 Connection Pool에 대해 개략적으로 알아보았습니다.

0개의 댓글