Loading...
Spring Framework Reference Documentation 7.0.2의 Resilience Features의 한국어 번역본입니다.
아래의 경우에 피드백에서 신고해주신다면 반영하겠습니다.
감사합니다 :)
7.0부터 core Spring Framework는 일반적인 resilience 기능을 포함하며, 특히
메서드 호출을 위한 @Retryable 및 @ConcurrencyLimit
어노테이션과 프로그래밍 방식 재시도 지원을 포함합니다.
@Retryable@Retryable은 개별 메서드(해당
어노테이션이 메서드 레벨에 선언된 경우)에 대한 재시도 특성 또는 주어진 클래스 계층
내에서 프록시에 의해 호출되는 모든 메서드(해당 어노테이션이 타입 레벨에 선언된
경우)에 대한 재시도 특성을 지정하는 어노테이션입니다.
1@Retryable 2public void sendNotification() { 3 this.jmsClient.destination("notifications").send(...); 4}
기본적으로, 메서드 호출은 발생한 모든 예외에 대해 재시도됩니다. 초기 실패 후
최대 3번의 재시도 시도(maxRetries = 3)가 이루어지며, 시도 간의 지연은 1초입니다.
@Retryable메서드는 최소 한 번 호출되며 최대maxRetries번까지 재시도됩니다. 여기서maxRetries는 재시도 시도의 최대 횟수입니다. 구체적으로,total attempts = 1 initial attempt + maxRetries attempts입니다. 예를 들어,maxRetries가4로 설정된 경우,@Retryable메서드는 최소 한 번 및 최대 5번 호출됩니다.
필요하다면, 각 메서드마다 이를 구체적으로 조정할 수 있습니다. 예를 들어,
includes 및 excludes attribute를 통해 재시도할 예외를 좁힐 수 있습니다.
제공된 예외 타입은 실패한 호출에 의해 발생한 예외뿐 아니라 중첩된 cause에
대해서도 매칭됩니다.
1@Retryable(MessageDeliveryException.class) 2public void sendNotification() { 3 this.jmsClient.destination("notifications").send(...); 4}
@Retryable(MessageDeliveryException.class)는@Retryable(includes = MessageDeliveryException.class)의 shortcut입니다.
고급 use case의 경우,
@Retryable의predicateattribute를 통해 customMethodRetryPredicate를 지정할 수 있으며, 이 predicate는 주어진Method와Throwable에 기반하여 실패한 메서드 호출을 재시도할지 여부를 결정하는 데 사용됩니다. 예를 들어,Throwable의 message를 검사할 수 있습니다. Custom predicate는includes및excludes와 조합할 수 있지만, custom predicate는 항상includes및excludes가 적용된 이후에 적용됩니다.
또는 4번의 재시도 시도와 약간의 jitter가 있는 exponential back-off 전략을 사용하는 예는 다음과 같습니다.
1@Retryable( 2 includes = MessageDeliveryException.class, 3 maxRetries = 4, 4 delay = 100, 5 jitter = 10, 6 multiplier = 2, 7 maxDelay = 1000) 8public void sendNotification() { 9 this.jmsClient.destination("notifications").send(...); 10}
마지막으로, @Retryable은 리액티브 반환 타입을 가진 리액티브 메서드에도 동작하며,
파이프라인을 Reactor의 재시도 기능으로 장식합니다.
1@Retryable(maxRetries = 4, delay = 100) 2public Mono<Void> sendNotification() { 3 return Mono.from(...); // (1) 4}
| 1 | 이 raw Mono는 재시도 spec으로 장식됩니다. |
다양한 특성에 대한 자세한 내용은
@Retryable에
사용 가능한 어노테이션 attribute를 참조하십시오.
@Retryable의 여러 attribute는 위의 예에서 사용된 구체적인 타입의 어노테이션 attribute에 대한 대안으로, 프로퍼티 플레이스홀더 및 SpEL을 지원하는Stringvariant를 제공합니다.
@ConcurrencyLimit@ConcurrencyLimit은
개별 메서드(해당 어노테이션이 메서드 레벨에 선언된 경우)에 대한 동시성 제한
또는 주어진 클래스 계층 내에서 프록시에 의해 호출되는 모든 메서드(해당 어노테이션이
타입 레벨에 선언된 경우)에 대한 동시성 제한을 지정하는 어노테이션입니다.
1@ConcurrencyLimit(10) 2public void sendNotification() { 3 this.jmsClient.destination("notifications").send(...); 4}
이는 target 리소스가 동시에 너무 많은 스레드에서 접근되는 것을 방지하기 위한 것으로, 스레드 풀 또는 커넥션 풀에 대한 풀 사이즈 제한이 그 제한에 도달했을 때 접근을 차단하는 것과 유사한 효과를 제공합니다.
선택적으로 제한을 1로 설정하여 target 빈 인스턴스에 대한 접근을 사실상
lock할 수 있습니다.
1@ConcurrencyLimit(1) 2public void sendNotification() { 3 this.jmsClient.destination("notifications").send(...); 4}
이러한 제한은 일반적으로 스레드 풀 제한이 존재하지 않는 Virtual Threads와 함께
특히 유용합니다. 비동기 태스크의 경우,
SimpleAsyncTaskExecutor에
이를 제약할 수 있습니다. 동기 호출의 경우, 이 어노테이션은
ConcurrencyThrottleInterceptor을
통해 동등한 동작을 제공하며, 이는 AOP framework와 함께 프로그래밍 방식으로 사용하기
위해 Spring Framework 1.0부터 제공되어 왔습니다.
@ConcurrencyLimit에는 위의int기반 예에 대한 대안으로, 프로퍼티 플레이스홀더 및 SpEL을 지원하는limitStringattribute도 있습니다.
Spring의 많은 core 어노테이션 기반 기능과 마찬가지로, @Retryable 및
@ConcurrencyLimit은 사용자가 이를 적용할지 무시할지 선택할 수 있는 메타데이터로
설계되었습니다. Resilience 어노테이션 처리를 활성화하는 가장 편리한 방법은
해당 @Configuration 클래스에
@EnableResilientMethods를
선언하는 것입니다.
또는, 이러한 어노테이션은 context에 RetryAnnotationBeanPostProcessor 또는
ConcurrencyLimitBeanPostProcessor 빈을 정의하여 개별적으로 활성화할 수
있습니다.
빈이 ApplicationContext에 등록되어 있는 메서드에 대해 재시도 의미를 지정하기
위한 선언적 접근 방식을 제공하는
@Retryable과
달리,
RetryTemplate은
임의의 코드 블록을 재시도하기 위한 프로그래밍 방식 API를 제공합니다.
구체적으로, RetryTemplate은 구성된
RetryPolicy에
따라 Retryable operation을 실행하고 필요에 따라
재시도합니다.
1var retryTemplate = new RetryTemplate(); // (1) 2 3retryTemplate.execute( 4 () -> jmsClient.destination("notifications").send(...));
| 1 | 암묵적으로 RetryPolicy.withDefaults()를 사용합니다. |
기본적으로, 재시도 가능한 operation은 발생한 모든 예외에 대해 재시도됩니다. 초기
실패 후 최대 3번의 재시도 시도(maxRetries = 3)가 이루어지며, 시도 간의 지연은
1초입니다.
재시도 시도 횟수만 custom하면 되는 경우, 아래에示된 것처럼
RetryPolicy.withMaxRetries() 팩터리 메서드를 사용할 수 있습니다.
재시도 가능한 operation은 최소 한 번 실행되며 최대
maxRetries번까지 재시도됩니다. 여기서maxRetries는 재시도 시도의 최대 횟수입니다. 구체적으로,total attempts = 1 initial attempt + maxRetries attempts입니다. 예를 들어,maxRetries가4로 설정된 경우, 재시도 가능한 operation은 최소 한 번 및 최대 5번 호출됩니다.
1var retryTemplate = new RetryTemplate(RetryPolicy.withMaxRetries(4)); // (1) 2 3retryTemplate.execute( 4 () -> jmsClient.destination("notifications").send(...));
| --- | |
|---|---|
| 1 | 명시적으로 RetryPolicy.withMaxRetries(4)를 사용합니다. |
재시도할 예외 타입을 좁힐 필요가 있는 경우, includes() 및 excludes()
빌더 메서드를 통해 이를 달성할 수 있습니다. 제공된 예외 타입은 실패한
operation에 의해 발생한 예외뿐 아니라 중첩된 cause에 대해서도 매칭됩니다.
1var retryPolicy = RetryPolicy.builder() 2 .includes(MessageDeliveryException.class) // (1) 3 .excludes(...) // (2) 4 .build(); 5 6var retryTemplate = new RetryTemplate(retryPolicy); 7 8retryTemplate.execute( 9 () -> jmsClient.destination("notifications").send(...));
| 1 | 포함할 하나 이상의 예외 타입을 지정합니다. |
| 2 | 제외할 하나 이상의 예외 타입을 지정합니다. |
고급 use case의 경우,
RetryPolicy.Builder의predicate()메서드를 통해 customPredicate<Throwable>을 지정할 수 있으며, 이 predicate는 주어진Throwable에 기반하여 실패한 operation을 재시도할지 여부를 결정하는 데 사용됩니다. 예를 들어,Throwable의 message를 검사할 수 있습니다. Custom predicate는includes및excludes와 조합할 수 있지만, custom predicate는 항상includes및excludes가 적용된 이후에 적용됩니다.
다음 예는 4번의 재시도 시도와 약간의 jitter가 있는 exponential back-off 전략을
사용하도록 RetryPolicy를 구성하는 방법을 보여줍니다.
1var retryPolicy = RetryPolicy.builder() 2 .includes(MessageDeliveryException.class) 3 .maxRetries(4) 4 .delay(Duration.ofMillis(100)) 5 .jitter(Duration.ofMillis(10)) 6 .multiplier(2) 7 .maxDelay(Duration.ofSeconds(1)) 8 .build(); 9 10var retryTemplate = new RetryTemplate(retryPolicy); 11 12retryTemplate.execute( 13 () -> jmsClient.destination("notifications").send(...));
RetryListener는 주요 재시도 phase(재시도 전, 재시도 후 등) 동안 발행되는 event에 반응하기 위해RetryTemplate에 등록될 수 있으며, 여러 listener를CompositeRetryListener를 통해 조합할 수 있습니다.
RetryPolicy에 대한 팩터리 메서드 및 빌더 API는 대부분의 일반적인
설정 시나리오를 다루지만, 재시도를 trigger해야 하는 예외 타입과
사용할 BackOff 전략에 대해 완전한 제어가
필요한 경우 custom RetryPolicy를 구현할 수 있습니다. 또한
RetryPolicy.Builder의 backOff() 메서드를 통해 custom BackOff 전략을
구성할 수도 있습니다.
Defining New Advice Types
Null-safety