-
[HikariCP] connectionTimeout 설정 알아보기Java 2024. 7. 11. 05:56반응형
- 목차
connectionTimeout 이란 ?
HikariPool 은 Java 에서 사용하는 Connection Pool 모듈입니다.
지정된 갯수만큼 많은 양의 Connection 을 미리 생성해두며, 생성된 Connection 을 하나씩 사용할 수 있습니다.
아래의 이미지는 2개의 Connection 이 존재하고, 3번의 Connection 요청이 발생하는 상황입니다.
Connection Pool 에서 Connection 을 요청한 2개의 Client 또는 Thread 는 정상적으로 Connection 을 사용할 수 있습니다.
반면 3번째 Client 또는 Thread 는 Connection Pool 에 더 이상 Connection 이 없기 때문에 Connection 을 획득할 수 없습니다.
이 상황에서 특정 시간동안 3번째 Client 또는 Thread 가 Connection 을 획득하지 못한다면 SQLTransientConnectionException 이 발생합니다.
이러한 예외 상황의 기준이 되는 Connection 획득 시간제한이 바로 Connection Timeout 이됩니다.
ConnectionTimeout 상황.
아래의 코드는 2개의 Connection 을 가지는 Connection Pool 과 3개의 Connection 요청을 구현한 코드입니다.
Connection 의 요청와 Connection Pool 용량이 서로 비대칭인 상태를 만들고, Connection Timeout 의 상황을 재현합니다.
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLTransientConnectionException; public class HikariCPExample { public static void main(String[] args) { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://mysql:3306/mysql"); config.setUsername("root"); config.setPassword("1234"); config.setConnectionTimeout(5000); // 연결 타임아웃 5초 config.setMaximumPoolSize(2); // 최대 커넥션 개수 2개 HikariDataSource dataSource = new HikariDataSource(config); try { long start, end, duration; // 첫 번째 Connection start = System.nanoTime(); Connection conn1 = dataSource.getConnection(); end = System.nanoTime(); duration = (end - start) / 1_000_000; // 나노초 -> 밀리초 변환 System.out.println("✅ Connection 1 획득 시간: " + duration + "ms"); // 두 번째 Connection start = System.nanoTime(); Connection conn2 = dataSource.getConnection(); end = System.nanoTime(); duration = (end - start) / 1_000_000; System.out.println("✅ Connection 2 획득 시간: " + duration + "ms"); // 세 번째 Connection (최대 풀 크기 초과) start = System.nanoTime(); try { Connection conn3 = dataSource.getConnection(); end = System.nanoTime(); duration = (end - start) / 1_000_000; System.out.println("✅ Connection 3 획득 시간: " + duration + "ms"); } catch (SQLTransientConnectionException e) { end = System.nanoTime(); duration = (end - start) / 1_000_000; System.out.println("⚠️ Connection 3 획득 실패 (소요 시간: " + duration + "ms) - " + e.getMessage()); } // 연결 닫기 conn1.close(); conn2.close(); } catch (SQLException e) { System.out.println("❌ SQL 예외 발생: " + e.getMessage()); e.printStackTrace(); } finally { dataSource.close(); } } }
Connection Timeout 을 5초로 설정하였기 때문에 세번째 Connection 을 요청하는 코드는 5초 간의 Blocking Time 이 발생하게 됩니다.
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@45c7e403 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. ✅ Connection 1 획득 시간: 0ms ✅ Connection 2 획득 시간: 14ms ⚠️ Connection 3 획득 실패 (소요 시간: 5026ms) - HikariPool-1 - Connection is not available, request timed out after 5008ms (total=2, active=2, idle=0, waiting=0) [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
MySQL 의 max_connections 갯수와 Connection Pool 의 관계.
데이터베이스가 허용하는 Connection 의 최대치보다 Connection Pool 의 사이즈가 더 큰 경우에 Connection Timeout 의 상황을 똑같이 발생합니다.
MySQL 의 경우에 max_connections 라는 설정으로 MySQL 이 허용하는 Connection 의 최대치가 존재합니다.
의도적으로 max_connections 의 값을 3개로 고정하고, HikariPool DataSource 의 풀 사이즈를 10개로 설정합니다.
show variables like 'max_connections'; +-----------------+-------+ | Variable_name | Value | +-----------------+-------+ | max_connections | 3 | +-----------------+-------+ 1 row in set (0.00 sec)
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import java.sql.Connection; import java.sql.SQLException; import java.sql.SQLTransientConnectionException; public class HikariCPExample { public static void main(String[] args) { HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:mysql://mysql:3306/mysql"); config.setUsername("root"); config.setPassword("1234"); config.setConnectionTimeout(5000); // 연결 타임아웃 5초 config.setMaximumPoolSize(10); // 최대 커넥션 개수 10개 HikariDataSource dataSource = new HikariDataSource(config); try { Connection conn1 = dataSource.getConnection(); Connection conn2 = dataSource.getConnection(); Connection conn3 = dataSource.getConnection(); Connection conn4 = dataSource.getConnection(); Connection conn5 = dataSource.getConnection(); Connection conn6 = dataSource.getConnection(); } catch (SQLException e) { System.out.println("❌ SQL 예외 발생: " + e.getMessage()); e.printStackTrace(); } finally { dataSource.close(); } } }
아래의 출력 내용을 확인해보면 max_connections 의 사이즈가 3이기 때문에 HikariPool DataSource 의 Total Connection 의 갯수도 3으로 설정됩니다.
MaximumPoolSize 가 10으로 설정되었어도 데이터베이스의 설정을 따릅니다.
그리고 Connection Timeout 시간이 흐른 후에 Connection 획득에 실패하고 SQLTransientConnectionException 을 Raise 합니다.
[main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting... [main] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection com.mysql.cj.jdbc.ConnectionImpl@45c7e403 [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed. ❌ SQL 예외 발생: HikariPool-1 - Connection is not available, request timed out after 5006ms (total=3, active=3, idle=0, waiting=0) java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 5006ms (total=3, active=3, idle=0, waiting=0) at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:686) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:179) at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:144) at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:99) at HikariCPExample.main(HikariCPExample.java:23) Caused by: java.sql.SQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections" at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:111) at com.mysql.cj.jdbc.exceptions.SQLExceptionsMapping.translateException(SQLExceptionsMapping.java:122) at com.mysql.cj.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:825) at com.mysql.cj.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:446) at com.mysql.cj.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:239) at com.mysql.cj.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:188) at com.zaxxer.hikari.util.DriverDataSource.getConnection(DriverDataSource.java:137) at com.zaxxer.hikari.pool.PoolBase.newConnection(PoolBase.java:360) at com.zaxxer.hikari.pool.PoolBase.newPoolEntry(PoolBase.java:202) at com.zaxxer.hikari.pool.HikariPool.createPoolEntry(HikariPool.java:461) at com.zaxxer.hikari.pool.HikariPool$PoolEntryCreator.call(HikariPool.java:724) at com.zaxxer.hikari.pool.HikariPool$PoolEntryCreator.call(HikariPool.java:703) at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) at java.base/java.lang.Thread.run(Thread.java:829) [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated... [main] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.
관련 코드.
docker network create mysql docker run -d --platform linux/amd64 --network mysql --name mysql --hostname mysql -e MYSQL_ROOT_PASSWORD=1234 mysql:8.0.23 docker run -it --network mysql --rm -v /tmp/HikariCPExample.java:/tmp/HikariCPExample.java openjdk:11 /bin/bash cd /tmp/ wget https://repo1.maven.org/maven2/com/zaxxer/HikariCP/5.1.0/HikariCP-5.1.0.jar wget https://repo1.maven.org/maven2/org/slf4j/slf4j-api/1.7.36/slf4j-api-1.7.36.jar wget https://repo1.maven.org/maven2/org/slf4j/slf4j-simple/1.7.36/slf4j-simple-1.7.36.jar wget https://repo1.maven.org/maven2/com/mysql/mysql-connector-j/8.0.33/mysql-connector-j-8.0.33.jar -P /tmp javac -cp HikariCP-5.1.0.jar:slf4j-api-1.7.36.jar:slf4j-simple-1.7.36.jar:mysql-connector-j-8.0.33.jar HikariCPExample.java java -cp .:HikariCP-5.1.0.jar:slf4j-api-1.7.36.jar:slf4j-simple-1.7.36.jar:mysql-connector-j-8.0.33.jar HikariCPExample
반응형'Java' 카테고리의 다른 글
[HikariCP] keepaliveTime 와 관련된 여러가지 실험 (0) 2024.07.22 [HikariCP] idleTimeout 알아보기 (0) 2024.07.18 [Java Serialization] 여러가지 자바 직렬화 해석 방식들 (0) 2024.07.06 Java ReentrantLock 알아보기 (0) 2024.06.03 [Java] 익명 클래스와 메모리 관계 알아보기 ( Anonymous Class , Method Area ) (0) 2024.06.02