본문 바로가기

CS study/spring

[HikariCP][DataSource]HikariDataSource/HikariPool, 그리고 동작 과정

목차

    HikariDataSource와 HikariPool

    HikariDataSource

     

    HikariDataSource는 DataSource 구현체이다.

     

    HikariCP를 사용하여 DataSource를 구현할 경우, 구체적인 구현체는 이 클래스가 된다.

    이렇게 구현되어, Bean 인스턴스에 들어가 관리되는 것이다.

     

    애플리케이션의 Config를 담당하기도 한다.

    application.properties 또는 application.yml 파일에 커넥션 풀 관련 설정(최대 커넥션 개수, 최소 유휴 커넥션 개수 등)을 지정할 때, 이 설정들은 com.zaxxer.hikari.HikariDataSource 인스턴스를 통해 관리된다.

     

    HikariDataSource 인스턴스는 HikariCP 커넥션 풀의 구성과 상태 관리를 담당하며, 이 인스턴스를 통해 데이터베이스 커넥션을 획득하고 반환하는 작업이 이루어진다. 

     

    HikariDataSource 인스턴스는 싱글톤으로 최대 한 개만 생성된다.

    이 인스턴스는 애플리케이션 전체에서 공유되며, 데이터베이스 커넥션을 관리하는 중앙 집중식 역할을 한다.

    즉, Heap에 저장된 이후 모든 Application에서 이 객체를 호출하여 공유하며 사용한다.

     

     

    커넥션 풀의 개수(CP)

    커넥션 풀의 개수HikariDataSource 인스턴스가 관리하는 데이터베이스 커넥션들의 최대 개수를 의미한다.

     

    설정에서 지정한 cp.max 값은 이 커넥션 풀에서 동시에 관리할 수 있는 최대 커넥션 수를 지정한다.

    실제로 HikariDataSource 내부에서는 HikariPool 객체를 사용하여 이 커넥션 풀을 관리하며, 여기서 커넥션의 생성, 재사용, 폐기 등을 적절히 처리한다.

     

    즉, CP = HikariDataSource 내부 필드 HikariPool이 가진 Connection 객체들의 개수를 의미한다.

     

    Connection 객체(Proxy) 관리: HikariPool은 실제 데이터베이스와의 커넥션을 위한 Connection 객체들을 관리한다. cp.max가 10으로 설정되어 있으면, 이 풀은 최대 10개의 데이터베이스 커넥션을 동시에 유지할 수 있다. 애플리케이션에서 데이터베이스 작업을 요청할 때, HikariDataSourceHikariPool로부터 사용 가능한 Connection 객체를 할당받는다. 작업이 완료되면, 이 커넥션은 풀로 반환되어 다른 요청에서 재사용될 수 있다.

     

     

    HikariPool

     

    HikariPool은 HikariCP 커넥션 풀 라이브러리 내부에서 실제로 데이터베이스 커넥션들을 관리하는 핵심 컴포넌트이다.

     

    HikariPool의 주요 기능 및 특징

    1. 커넥션 관리 

    HikariPool은 설정된 최대 커넥션 수(maximumPoolSize)와 최소 유휴 커넥션 수(minimumIdle)에 따라 데이터베이스 커넥션을 관리한다. 필요에 따라 새로운 커넥션을 생성하거나, 유휴 상태의 커넥션을 폐기하여 리소스를 효율적으로 사용한다.

     

    2. 커넥션 할당 및 반환

    애플리케이션에서 데이터베이스 작업을 위해 커넥션을 요청할 때, HikariPool은 사용 가능한 커넥션을 할당한다. 작업 완료 후, 커넥션은 풀로 반환되어 다른 요청에서 재사용될 수 있다.

     

    3. 성능 최적화

    HikariPool은 매우 빠른 커넥션 할당 및 반환을 위해 최적화되어 있다. HikariCP는 "가장 빠른" 커넥션 풀 라이브러리 중 하나로 알려져 있으며, 이는 HikariPool의 효율적인 구현 덕분이다.

     

    4. 상태 모니터링 및 헬스 체크

    HikariPool은 커넥션의 상태를 주기적으로 검사하고, 비정상적인 커넥션을 감지하여 자동으로 대체한다. 이를 통해 데이터베이스 연결의 안정성을 보장한다.

     

    5. 구성 및 커스터마이징: HikariPool은 HikariConfig를 통해 다양한 설정을 제공한다. 이를 통해 개발자는 커넥션 풀의 동작을 자신의 애플리케이션 요구사항에 맞게 세밀하게 조정할 수 있다.

     

    HikariPool 내부 동작 방식

    HikariPool은 내부적으로 여러 개의 PoolEntry 객체를 관리하는데, 각 PoolEntry 객체는 하나의 데이터베이스 커넥션을 감싸는 래퍼이다.

    아래는 HikariPool의 getConnection 메서드이다.

     

    HikariPool은 이러한 PoolEntry 객체들을 통해 커넥션의 생성, 유휴 상태 관리, 폐기 등을 수행한다.

    커넥션 풀에서 커넥션을 요청하는 과정은 HikariPool이 관리하는 이러한 PoolEntry 객체들 중 하나를 선택하거나, 필요한 경우 새로운 PoolEntry를 생성하여 처리한다.

     

     

    실제 동작 과정

     

    이런 식으로 변조를 통해, 모든 라이브러리의 동작 코드를 출력하게 하였다.

     

    다음은 바이트코드로 로깅을 추가하여, 실제 쿼리 실행시 어떻게 동작하는지 과정을 통해 알아본다.


    1. 커넥션 획득


    애플리케이션은 HikariPool을 통해 데이터베이스 커넥션을 요청(getConnection). 
    이 과정에서 HikariPool은 사용 가능한 커넥션을 풀에서 찾거나 새로운 커넥션을 생성한다.

    [class/method] : com/zaxxer/hikari/pool/HikariPool : getConnection 
    [class/method] : com/zaxxer/hikari/pool/HikariPool : getConnection
    [class/method] : com/zaxxer/hikari/pool/PoolEntry : compareAndSet
    [class/method] : com/zaxxer/hikari/pool/PoolEntry : isMarkedEvicted
    [class/method] : com/zaxxer/hikari/pool/PoolBase$SynchronousExecutor : execute
    [class/method] : com/zaxxer/hikari/pool/PoolBase$SynchronousExecutor : execute
    [class/method] : com/zaxxer/hikari/pool/ProxyLeakTaskFactory : schedule
    [class/method] : com/zaxxer/hikari/pool/PoolEntry : createProxyConnection
    [class/method] : com/zaxxer/hikari/pool/ProxyFactory : getProxyConnection



    2. 커넥션 상태 설정


    커넥션의 자동 커밋(getAutoCommit, setAutoCommit) 상태가 확인 및 설정된다. 
    이는 트랜잭션 관리를 위해 중요한 단계이다.

    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : <init>
    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : getAutoCommit
    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : setAutoCommit


    3. SQL 쿼리 준비


    HikariProxyConnection을 통해 prepareStatement 메서드가 호출되어 SQL 쿼리를 준비한다. 
    이 때 ProxyFactory를 사용하여 실제 PreparedStatement 대신 프록시 객체(HikariProxyPreparedStatement)를 생성한다.

    Hibernate: select sd1_0.no,sd1_0.etc,sd1_0.send_time from sql_dummy sd1_0 limit ?,? //실제 준비되는 SQL 쿼리 예시
    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : prepareStatement
    [class/method] : com/zaxxer/hikari/pool/ProxyFactory : getProxyPreparedStatement



    4. 쿼리 파라미터 설정


    HikariProxyPreparedStatement에 대해 setInt, setString 등의 메서드를 호출하여 SQL 쿼리의 파라미터를 설정한다.

    [class/method] : com/zaxxer/hikari/pool/HikariProxyPreparedStatement : <init>
    [class/method] : com/zaxxer/hikari/pool/HikariProxyPreparedStatement : setInt
    [class/method] : com/zaxxer/hikari/pool/HikariProxyPreparedStatement : setInt


    5. 쿼리 실행 및 결과 처리

    executeQuery 메서드를 통해 쿼리가 실행되고, 결과는 HikariProxyResultSet으로 반환된다. 
    next, getLong, getString, getTimestamp 등의 메서드를 호출하여 결과 데이터를 순차적으로 처리한다.

    [class/method] : com/zaxxer/hikari/pool/HikariProxyPreparedStatement : executeQuery //쿼리 실행
    [class/method] : com/zaxxer/hikari/pool/ProxyFactory : getProxyResultSet //ResultSet 프록시 객체 가져옴
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : <init>
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : next
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : getLong
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : wasNull
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : getString
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : getTimestamp
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : wasNull
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : next

     

     

    6. 자원 정리 

    쿼리 실행 후, HikariProxyResultSet과 HikariProxyPreparedStatement 객체는 각각 close와 isClosed 메서드를 통해 정리된다. 
    이는 리소스 누수를 방지하고 풀의 커넥션을 효율적으로 재사용하기 위한 중요한 단계이다.

    [class/method] : com/zaxxer/hikari/pool/HikariProxyPreparedStatement : isClosed
    [class/method] : com/zaxxer/hikari/pool/HikariProxyResultSet : close


    6-1. 쿼리 실행 전후나 커넥션 반환 과정에서 커넥션의 상태를 확인하거나 설정하기 위해 호출

    => HikariCP 내부에서 커넥션을 재사용하기 전에 해당 커넥션의 상태를 확인하고 초기화하는 과정의 일부로 추측된다. 

    (확실한 것은 아님)

    //쿼리 실행 결과로 반환될 수 있는 최대 행 수를 제한
    [class/method] : com/zaxxer/hikari/pool/HikariProxyPreparedStatement : getMaxRows
    //SQL 쿼리가 실행되는 최대 시간(초 단위)을 반환
    [class/method] : com/zaxxer/hikari/pool/HikariProxyPreparedStatement : getQueryTimeout

     

     

    7. 트랜잭션 커밋

    트랜잭션이 성공적으로 완료되면, HikariProxyConnection의 commit 메서드를 호출하여 데이터베이스에 변경사항을 커밋한다.

    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : commit
    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : setAutoCommit
    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : isClosed
    [class/method] : com/zaxxer/hikari/pool/HikariProxyConnection : clearWarnings

     

     

    8. 커넥션 상태 초기화 및 pool 반환 

    마지막으로, PoolEntry의 resetConnectionState와 recycle 메서드를 통해 커넥션 상태를 초기화하고, 커넥션을 풀로 반환한다. 


    HikariPool의 recycle 메서드도 이 과정에 관여한다.

    [class/method] : com/zaxxer/hikari/pool/ProxyLeakTask$1 : cancel
    [class/method] : com/zaxxer/hikari/pool/PoolEntry : resetConnectionState
    [class/method] : com/zaxxer/hikari/pool/PoolEntry : recycle
    [class/method] : com/zaxxer/hikari/pool/HikariPool : recycle
    [class/method] : com/zaxxer/hikari/pool/PoolEntry : setState

     

     

    9. 풀 상태 및 유지 관리

    'HikariPool$HouseKeeper'의 run 메서드를 통해 주기적으로 커넥션 풀의 상태를 점검하고, 필요한 유지보수 작업을 수행한다. 
    이는 커넥션 풀의 정상적인 동작을 유지하기 위한 중요한 과정이다.

    [class/method] : com/zaxxer/hikari/pool/HikariPool$HouseKeeper : run
    [class/method] : com/zaxxer/hikari/pool/ProxyLeakTaskFactory : updateLeakDetectionThreshold
    [class/method] : com/zaxxer/hikari/pool/HikariPool : logPoolState
    [class/method] : com/zaxxer/hikari/pool/HikariPool : fillPool
    [class/method] : com/zaxxer/hikari/pool/HikariPool : getTotalConnections





     

     

     

    'CS study > spring' 카테고리의 다른 글

    인터셉터와 AOP의 차이, 인터셉터의 추가 개념  (1) 2023.11.26
    AOP의 개념과 적용하기  (0) 2023.11.22
    인터셉터(Interceptor)란?  (0) 2023.10.29