Spring Boot 는 기본적으로 최소 10개, 최대 200개의 쓰레드를 사용할 수 있고, 최대 8192개의 커넥션이 가능하고, 100 size의 큐를 갖고 있다.
물론 개발자가 튜닝할 수 있는 영역이긴 하지만, 우리 프로젝트에서는 아직 서버 튜닝의 입지는 아니기에.. 모든걸 default로 설정하였다.
그런데, WAS 에서 유저가 얼마 있지도 않음에도 다음과 같이 커넥션을 연결하지 못한 채 타임아웃이 나버렸다.
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available
기본적으로 HikariCP 는 최대 10개의 DB 커넥션을 지원하고 있다.
이 때 동료중의 한명은 말을 했었다.
하나의 페이지에서 여러 API 를 요청함에 따라 Spring MVC 에서는 요청 별로 쓰레드를 할당하고, nginx를 통해 keep-alive를 90초로 설정해놓았기에
쓰레드에서 커넥션 풀을 잡고 놓아주지 않는 것은 아닐까?
그렇다면 유저도 얼마 없는데 30초 씩이나 DB 커넥션을 얻지 못할 일이 뭐가 있을까?
public static Array createSqlArray(JdbcTemplate template, List<String> tags) throws SQLException {
Array stringArray = null;
try {
stringArray = template.getDataSource().getConnection().createArrayOf("varchar", tags.toArray());
} catch (SQLException e) {
throw new SQLException(e);
}
return stringArray;
}
위 코드는 template 에서 datasource를 직접 꺼내고 직접 커넥션을 얻어 사용하였는데, 끝나고 반환을 하지 않았다.
위 같은 경우에 finally 구문에서 close 를 해주거나, try-with-resources 를 사용하는 방법으로 해결할 수 있다.
여기서 finally로 close를 해주는 것은 구식의 방법이므로 try-with-resources를 사용하였다.
이 때, AutoClosable을 직접 커스터마이징하여 구현할 수 도 있었지만. 당초에 AutoClosable을 구현하고 있는 것이 Connection이므로, 알아서 연결을 반환하게 된다.
고친 코드는 다음과 같다.
public static Array createSqlArray(JdbcTemplate template, List<String> tags) throws SQLException {
try (Connection con = template.getDataSource().getConnection()) {
return con.createArrayOf("varchar", tags.toArray());
} catch (SQLException e) {
throw new SQLException(e);
}
}
이렇게 try
구문 안에 close되길 원하는 객체를 선언하고 할당해주면, 해당 객체가 AutoClosable을 구현한 객체인 경우 알아서 close되어진다.
https://docs.oracle.com/javase/8/docs/api/java/lang/AutoCloseable.html
위 링크는, 구현된 객체들을 담은 공식문서이다.