본문으로 건너뛰기
Advertisement

2.12 재시도와 복원력 (Retry / Resilience4j)

외부 API·DB·메시지 브로커 호출은 일시적 장애로 실패할 수 있습니다. 재시도(Retry)서킷 브레이커로 실패를 흡수하고, 장애 전파를 줄일 수 있습니다.

작성 기준: Spring Boot 3.2.x, spring-retry 또는 Resilience4j

1. Spring Retry (@Retryable)

implementation 'org.springframework.retry:spring-retry'
@SpringBootApplication
@EnableRetry
public class Application { ... }
@Service
public class PaymentClient {

@Retryable(
retryFor = { RestClientException.class },
maxAttempts = 3,
backoff = @Backoff(delay = 1000, multiplier = 2)
)
public PaymentResult callExternalApi(PaymentRequest req) {
return restTemplate.postForObject(...);
}

@Recover // 모든 재시도 실패 후 호출
public PaymentResult recover(RestClientException e, PaymentRequest req) {
log.error("결제 API 호출 실패, 폴백", e);
return PaymentResult.failed("일시적 오류");
}
}
  • retryFor: 이 예외일 때만 재시도
  • maxAttempts: 최대 시도 횟수
  • backoff: 대기 시간 (delay ms, multiplier로 증가)
  • @Recover: 시그니처가 (Exception, 메서드 인자...)와 일치해야 함

2. Resilience4j — 서킷 브레이커

연속 실패 시 일정 시간 호출을 차단해 리소스를 보호하려면 Resilience4j를 사용합니다.

implementation 'io.github.resilience4j:resilience4j-spring-boot3'
resilience4j:
circuitbreaker:
instances:
paymentApi:
registerHealthIndicator: true
slidingWindowSize: 10
minimumNumberOfCalls: 5
failureRateThreshold: 50
waitDurationInOpenState: 10s
@Service
public class PaymentService {

private final CircuitBreaker circuitBreaker;
private final PaymentClient client;

public PaymentService(CircuitBreakerRegistry registry, PaymentClient client) {
this.circuitBreaker = registry.circuitBreaker("paymentApi");
this.client = client;
}

public PaymentResult pay(PaymentRequest req) {
return circuitBreaker.executeSupplier(() -> client.callExternalApi(req));
}
}
  • failureRateThreshold: 실패 비율이 이 값을 넘으면 서킷이 OPEN (호출 차단)
  • waitDurationInOpenState: OPEN 상태 유지 시간 후 HALF_OPEN으로 전환해 재시도

3. Retry + CircuitBreaker 조합

Resilience4j는 RetryCircuitBreaker를 같이 등록할 수 있습니다.
먼저 Retry로 몇 번 재시도하고, 그래도 실패율이 높으면 CircuitBreaker가 열리도록 구성하는 패턴이 많습니다.


재시도할 예외를 retryFor로 한정하고, 비즈니스 예외(4xx 등)는 재시도하지 않도록 구분하는 것이 좋습니다. 외부 의존성 타임아웃은 RestTemplate/WebClient 설정과 함께 조정하세요.

Advertisement