could not open JDBC Connection

JDBC 커넥션 오류. 또 너냐.
could not open JDBC Connection. 지겹게 보는 에러다.
원인은 다양하지만, 해결책은 보통 정해져 있다. 순서대로 확인하자.
1. 커넥션 풀 설정 조정
가장 먼저 볼 것. WAS의 커넥션 풀이 부족하면 당연히 에러가 난다. 부하에 비해 풀이 작지 않은지 확인한다.
application.yml (HikariCP 기준)
spring:
datasource:
hikari:
maximum-pool-size: 20 # 여기. 부하에 맞게 늘리자.
데이터베이스의 max_connections도 고려해야 한다. 무작정 늘리는 건 답이 아니다.
2. DB 커넥션이 잘 닫히는지 확인
기본 중의 기본. 커넥션 누수는 풀을 말려버린다. try-with-resources를 쓰면 실수는 줄어든다.
// 괄호 안에서 생성된 자원은 알아서 닫힌다.
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery()) {
// ... 로직 ...
} catch (SQLException e) {
// ... 예외 처리 ...
}
코드를 의심하자. 항상.
3. Slow Query나 Long Transaction 확인
느린 쿼리나 긴 트랜잭션은 커넥션을 오래 붙잡는다. 결국 다른 요청이 커넥션을 못 가져간다.
APM(Application Performance Management) 툴이 있으면 편하다.
없으면 DB 로그라도 뒤져봐야 한다.
4. 실제 max_connections 확인
DB가 최대로 허용하는 커넥션 수를 확인한다.
-- MySQL/MariaDB 기준
SHOW VARIABLES LIKE 'max_connections';
이 값보다 HikariCP의 maximum-pool-size가 크면 의미 없다.
4-1. 현재 커넥션 수와 비교
현재 DB에 연결된 커넥션 수도 확인해 보자.
-- MySQL/MariaDB 기준
SHOW STATUS LIKE 'Threads_connected';
max_connections에 근접하고 있다면 위험 신호다. 원인을 찾아야 한다.
5. spring-retry 적용
일시적인 네트워크 문제나 DB 장애로 커넥션을 못 가져올 수도 있다. 이럴 때 spring-retry는 유용하다. 몇 번 더 시도하고, 그래도 안 되면 실패 처리한다.
의존성 추가 (Maven)
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
@EnableRetry 추가
@Configuration
@EnableRetry
public class AppConfig {
// ...
}
서비스 메소드에 적용
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.Retryable;
import java.sql.SQLException;
@Service
public class MyService {
@Retryable(
value = {SQLException.class}, // SQLException 발생 시 재시도
maxAttempts = 3, // 최대 3번
backoff = @Backoff(delay = 2000) // 2초 간격으로
)
public void someDatabaseOperation() {
// ... DB 작업 ...
}
}
@Retryable은 만능이 아니다.
위의 모든 것이 안된다면 신중하게 사용해야 한다.
여기까지 확인하면 대부분 해결된다.
이제 퇴근하자.