Spring Batch 5.1.2에서 HikariCP 연결 문제 해결 방법

Spring Batch 5.1.2를 사용하면서 HikariCP 연결 문제를 경험하는 경우가 많습니다. 특히, 데이터베이스 재시작 또는 세션 종료 후 커넥션이 끊기는 문제가 발생할 수 있습니다. 이 글에서는 이러한 문제의 원인을 분석하고, 해결 방법을 소개하겠습니다.

1. 문제 원인 분석

Spring Batch는 배치 작업을 실행하면서 데이터베이스와 지속적으로 연결을 유지합니다. 하지만 다음과 같은 상황에서 HikariCP의 연결이 끊길 수 있습니다:

  • 데이터베이스가 재시작됨: 기존 연결이 유효하지 않음
  • 세션 타임아웃: 일정 시간 사용되지 않은 커넥션이 종료됨
  • 네트워크 문제: 일시적인 네트워크 단절
  • HikariCP의 기본 설정이 재연결을 보장하지 않음

이러한 경우 배치 작업이 실패할 수 있으며, Broken pipe, Connection reset, Communications link failure 등의 예외가 발생할 수 있습니다.

2. 데이터베이스 연결이 끊어졌을 때의 영향

데이터베이스 연결이 끊어지면 기존에 사용 중이던 커넥션과 트랜잭션은 다음과 같은 영향을 받습니다:

  1. 진행 중이던 트랜잭션이 롤백됨: 연결이 끊어진 상태에서는 트랜잭션이 정상적으로 커밋될 수 없으며, 자동으로 롤백됩니다.
  2. HikariCP가 기존 연결을 제거하고 새 커넥션을 할당: 하지만 새로운 연결이 할당되더라도, 이전 트랜잭션은 복구되지 않습니다.
  3. 배치 작업이 실패하고 예외 발생: Spring Batch 작업이 실패하고 SQLException이 발생할 수 있습니다.

3. 해결 방법

3.1 HikariCP 설정 조정

HikariCP의 기본 설정만으로는 자동 재연결이 보장되지 않습니다. 다음과 같은 설정을 추가하여 안정성을 높일 수 있습니다.

spring.datasource.hikari.maximum-pool-size=10
spring.datasource.hikari.minimum-idle=5
spring.datasource.hikari.idle-timeout=30000
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.max-lifetime=25200000  # 7시간 유지 (DB의 8시간보다 짧게 설정)
spring.datasource.hikari.keepalive-time=30000
  • max-lifetime: 데이터베이스 설정(예: 8시간)보다 짧게 설정하여 커넥션이 강제 종료되기 전에 갱신됨 (예: 7시간 또는 7시간 30분 권장)
  • keepalive-time: 사용 중이지 않은 커넥션도 주기적으로 갱신하여 유효성을 보장

3.2 Max Lifetime을 기준으로 한 설정 계산 방법

max-lifetime 설정을 적절히 조정하기 위해 데이터베이스의 연결 제한 시간(예: 8시간)을 기준으로 다른 설정 값을 계산할 수 있습니다.

  • 최적의 max-lifetime 설정: DB의 연결 제한 시간보다 5~10% 짧게 설정 (예: 8시간 설정 시, 7시간 또는 7시간 30분 설정)
  • keepalive-time** 조정**: max-lifetime의 1/10 ~ 1/5 정도로 설정하여 일정 주기마다 커넥션을 새로고침 (예: max-lifetime=7시간일 경우 keepalive-time=30분 설정)
  • Connection Timeout: 네트워크 상태에 따라 30초~60초로 설정하여 재연결 가능성을 높임
spring.datasource.hikari.max-lifetime=25200000  # 7시간 (DB의 8시간보다 짧게 설정)
spring.datasource.hikari.keepalive-time=1800000  # 30분 간격으로 커넥션 유지
spring.datasource.hikari.connection-timeout=60000  # 60초 내 응답 없을 경우 연결 시도 중단

이러한 계산법을 적용하면 불필요한 커넥션 종료를 방지하면서도 안정적인 연결을 유지할 수 있습니다.

3.3 Validation Query 추가 (선택 사항)

HikariCP는 기본적으로 keepalive-time 설정을 통해 연결을 유지하지만, 특정 환경에서는 validation-query 설정이 추가적으로 도움이 될 수 있습니다. MariaDB의 경우 다음 설정을 고려할 수 있습니다.

spring.datasource.hikari.validation-timeout=5000
spring.datasource.hikari.connection-test-query=SELECT 1

이 설정을 추가하면, HikariCP가 커넥션을 사용하기 전에 유효한지 체크합니다. 하지만 keepalive-time이 설정되어 있다면 꼭 필요한 것은 아닙니다.

3.4 Spring Retry 적용 전후 비교

Spring Retry를 적용하지 않은 경우, 배치 작업이 실패하고 트랜잭션이 롤백됩니다.

Spring Retry 미적용 코드 (트랜잭션 실패 예제)

@Transactional
public void executeBatchJob() {
    jdbcTemplate.update("INSERT INTO orders (order_id, status) VALUES (?, ?)", 1, "PENDING");
    // 데이터베이스 연결이 끊어지는 경우 예외 발생
    jdbcTemplate.update("UPDATE orders SET status = ? WHERE order_id = ?", "COMPLETED", 1);
}
  • DB 연결이 끊어지면 SQLException 발생
  • 트랜잭션이 롤백되어 첫 번째 INSERT 쿼리도 반영되지 않음

Spring Retry 적용 코드

@Retryable(value = SQLException.class, maxAttempts = 3, backoff = @Backoff(delay = 5000))
@Transactional
public void executeBatchJobWithRetry() {
    jdbcTemplate.update("INSERT INTO orders (order_id, status) VALUES (?, ?)", 1, "PENDING");
    jdbcTemplate.update("UPDATE orders SET status = ? WHERE order_id = ?", "COMPLETED", 1);
}
  • 최대 3회까지 재시도하며, 각 재시도는 5초 간격으로 실행됨
  • 트랜잭션 단위로 재시도되므로, 기존 작업이 롤백되고 처음부터 다시 실행됨
  • 재시도 성공 시 트랜잭션이 정상적으로 커밋됨

4. 결론

Spring Batch 5.1.2에서 HikariCP 연결 문제를 방지하려면 적절한 HikariCP 설정 조정, Max Lifetime을 기준으로 한 최적의 설정 계산, Validation Query 추가(선택 사항), Spring Retry 적용 등의 방법을 사용할 수 있습니다. 특히, Spring Retry를 적용하면 배치 작업 실패 시 자동 재시도를 통해 트랜잭션을 복구할 수 있습니다. 이를 통해 배치 작업이 보다 안정적으로 실행될 수 있도록 설정하는 것이 중요합니다.

이제 여러분의 Spring Batch 애플리케이션이 DB 연결 문제 없이 원활하게 동작하도록 설정해 보세요!

관련 글

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다