Spring

[Spring] HikariCP 동작 방식

누구세연 2024. 9. 29. 22:56

HikariCP의 성능과 효율성을 구체적으로 이해하고 이를 실제로 어떻게 구현했는지 파악해 보겠습니다.👀

 

HikariCP의 아키텍처

HikariCP는 간단한 설정을 통해 고성능 커넥션 풀링을 지원합니다. 내부적으로는 커넥션을 풀에 저장해 놓고 필요할 때마다 커넥션을 효율적으로 관리합니다. 그 과정을 관리하는 주요 클래스들은 다음과 같습니다.

  • HikariDataSource
    HikariCP의 시작점으로 기본 설정을 통해 커넥션 풀을 초기화하고 관리합니다.
  • HikariPool
    실제 커넥션 풀을 관리하며 커넥션을 빌려주고 반환하는 과정을 처리합니다.
  • PoolEntry
    풀내의 각각 커넥션을 표현하는 클래스입니다.
  • ProxyConnection
    데이터베이스와의 실제 커넥션을 감싸서 풀에 반환할 때 사용하는 래퍼 클래스입니다.

 

HikariDataSource의 동작 방식

HikariDataSource는 커넥션 풀을 초기화하는 중심적인 클래스입니다. 이 클래스의 역할과 어떻게 HikariPool과 연결되는지 설명할 수 있습니다.

public class HikariDataSource extends HikariConfig implements DataSource {
    private final HikariPool pool;
    
    public HikariDataSource(HikariConfig configuration) {
        super(configuration);
        this.pool = new HikariPool(this);
    }
    
    @Override
    public Connection getConnection() throws SQLException {
        return pool.getConnection();
    }
}
  • `HikariDataSource`는 HikariConfig를 상속받아 사용자 설정을 관리하고 HikariPool을 생성하여 커넥션 풀을 제어합니다.
  • `getConnection()`메서드를 호출하면 HikariPool에서 사용 가능한 커넥션을 반환합니다.

 

HikariPool의 동작

`HikariPool`클래스는 HikariCP의 핵심 클래스 중 하나로 실제 커넥션 풀을 관리하고 커넥션 할당 및 반환을 처리합니다.

내부적으로 LinkedBlockingQueue를 사용하여 풀을 구성하며 요청이 들어오면 즉시 사용한 커넥션을 제공하는 방식입니다.

public final class HikariPool {
    private final LinkedBlockingQueue<PoolEntry> connectionBag;
    
    public HikariPool(HikariConfig config) {
        this.connectionBag = new LinkedBlockingQueue<>(config.getMaximumPoolSize());
        initializeConnections(config);
    }
    
    public Connection getConnection() throws SQLException {
        PoolEntry entry = connectionBag.poll();
        return entry != null ? entry.createProxyConnection() : null;
    }
}
  • `connectionBag`: 커넥션을 저장하는 큐로 사용 가능한 커넥션을 관리합니다.
  • `initializeConnections`: 풀을 초기화하면서 미리 설정된 개수만큼 커넥션을 생성하여 풀에 저장합니다.
  • `getConnection`: 요청이 들어오면 풀에서 사용 가능한 커넥션을 가져오고 없을 경우 null을 반환하거나 대기하게 할 수 있습니다.

 

ProxyConnection의 역할

HikariCP는 풀에서 빌려간 커넥션을 다시 풀로 반환할 수 있도록 Proxy 패턴을 활용합니다.

ProxyConnection 클래스는 진짜 데이터베이스 커넥션을 감싸는 역할을 합니다.

public class ProxyConnection implements Connection {
    private final Connection delegate;
    private final HikariPool pool;
    
    public ProxyConnection(Connection delegate, HikariPool pool) {
        this.delegate = delegate;
        this.pool = pool;
    }

    @Override
    public void close() throws SQLException {
        pool.releaseConnection(this);
    }
}
  • `ProxyConnection`은 실제로 데이터베이스에 연결된 커넥션을 감싸고 있습니다. 사용자는 이 커넥션을 통해 쿼리를 실행하고 커넥션을 반환할 때 `close()`메서드를 호출합니다.
  • `close()`메서드는 진짜로 커넥션을 닫는 대신 풀로 다시 반환합니다.

 

Connection Timeout과 Pool Size 설정의 처리

HikariCP가 빠른 커넥션 풀로 알려진 중요한 이유 중 하나는 Connection Timeout과 Maximum Pool Size를 정교하게 처리하기 때문입니다.

config.setConnectionTimeout(30000); // 30초 대기
config.setMaximumPoolSize(10); // 최대 10개의 커넥션
  • Connection Timeout
    HikariCP는 커넥션을 기다리는 시간을 제어할 수 있는 타임아웃을 제공합니다.
    설정한 시간 내에 커넥션을 얻지 못하면 예외가 발생합니다.
  • Pool Size
    Maximum Pool Size는 풀 내에 동시에 유지할 수 있는 커넥션의 최대 수를 정의합니다.
    HikariCP는 이 수치를 유지하며 필요시 풀을 확장 또는 축소할 수 있습니다.

 

HikariCP의 성능 최적화

HikariCP의 주요 성능 최적화 포인트는 다음과 같습니다.

  • Fast Fail
    커넥션을 특히 사용할 수 없다면 빠르게 실패하고 긴 대기 시간을 방지합니다.
  • Efficient Connection Handling
    커넥션을 반환할 때 풀로 다시 반환하고 바로 사용할 수 있도록 설계되어 대기 시간을 줄입니다.
  • Lightweight Objects
    HikariCP는 불필요한 객체 생성을 줄여 메모리 사용량을 최소화하고 가비지 컬렉션의 부담을 덜어줍니다.

 

💡 내부적으로 효율적인 커넥션 관리와 최적화된 성능을 위해 다양한 기술들이 사용되고 있으며, 이 구조 덕분에 HikariCP가 높은 성능을 자랑하는 커넥션 풀로 자리 잡고 있습니다.