Retry Pattern 구현(2)

날아올라돼지야·2024년 8월 29일
0

1. Retry Pattern 개요 및 설정

이번 강의에서는 AccountsController 내부에서 Retry Pattern을 구현하는 방법을 다룹니다. 이전에는 Gateway Server에서 Retry Pattern을 적용했지만, 개별 마이크로서비스에서도 이 패턴을 구현할 수 있습니다. 이번에는 build-info API를 선택하여 Retry Pattern을 적용할 것입니다.

2. Retry Pattern 설정

Retry Pattern을 설정하기 위해 @Retry 애노테이션을 사용합니다. 이 애노테이션을 통해 재시도 횟수와 fallback 메서드를 지정할 수 있습니다.

2.1 Retry 애노테이션 설정

먼저, build-info API에 Retry Pattern을 적용합니다.

@RestController
public class AccountsController {

    @GetMapping("/build-info")
    @Retry(name = "getBuildInfo", fallbackMethod = "getBuildInfoFallback")
    public String getBuildInfo() {
        logger.debug("Invoked getBuildInfo method");
        throw new NullPointerException("Simulated Exception");
    }

    public String getBuildInfoFallback(Throwable t) {
        logger.debug("Invoked getBuildInfoFallback method due to: " + t.getMessage());
        return "0.9"; // fallback으로 반환할 버전 정보
    }
}
  • @Retry(name = "getBuildInfo", fallbackMethod = "getBuildInfoFallback"): 이 애노테이션은 build-info API에 Retry Pattern을 적용합니다. getBuildInfo라는 이름으로 패턴을 정의하며, 실패 시 호출될 fallback 메서드로 getBuildInfoFallback을 지정합니다.
  • getBuildInfoFallback(Throwable t): fallback 메서드로, 예외 발생 시 호출됩니다. 메서드 시그니처는 원래 메서드와 동일하게 유지하되, 추가로 Throwable을 인자로 받아야 합니다.

3. Retry Pattern 구성 설정

application.yml 파일에서 Retry Pattern에 대한 설정을 추가합니다.

3.1 application.yml에 Retry Pattern 설정 추가

resilience4j:
  retry:
    configs:
      default:
        max-attempts: 3 # 최대 3회 재시도
        wait-duration: 500ms # 각 재시도 간 대기 시간
        exponential-backoff:
          enabled: true # 백오프 전략 사용
          multiplier: 2 # 백오프 증가 비율
  • max-attempts: 3: 최대 3번의 재시도를 허용합니다.
  • wait-duration: 500ms: 각 재시도 간 대기 시간을 500ms로 설정합니다.
  • exponential-backoff: 백오프 전략을 활성화하여, 각 재시도 시 대기 시간을 배수로 증가시킵니다.

4. 로그 추가 및 예외 발생

재시도 동작을 확인하기 위해 로그를 추가하고, NullPointerException을 발생시킵니다.

4.1 로그 및 예외 처리

@RestController
public class AccountsController {

    private static final Logger logger = LoggerFactory.getLogger(AccountsController.class);

    @GetMapping("/build-info")
    @Retry(name = "getBuildInfo", fallbackMethod = "getBuildInfoFallback")
    public String getBuildInfo() {
        logger.debug("Invoked getBuildInfo method");
        throw new NullPointerException("Simulated Exception");
    }

    public String getBuildInfoFallback(Throwable t) {
        logger.debug("Invoked getBuildInfoFallback method due to: " + t.getMessage());
        return "0.9"; // fallback으로 반환할 버전 정보
    }
}
  • logger.debug()를 사용하여 메서드가 호출될 때마다 로그를 출력합니다.
  • NullPointerException을 의도적으로 발생시켜, 재시도와 fallback 메서드 호출을 확인합니다.

5. 애플리케이션 실행 및 테스트

5.1 애플리케이션 빌드 및 재시작

애플리케이션을 빌드하고 재시작합니다.

# Accounts 애플리케이션 빌드 및 재시작
./mvnw clean install -DskipTests
java -jar target/accounts-ms.jar

# Gateway Server 애플리케이션 빌드 및 재시작
./mvnw clean install -DskipTests
java -jar target/gateway-server.jar

5.2 Postman을 사용한 테스트

Postman에서 build-info API를 호출하여 Retry Pattern을 테스트합니다.

{
    "response": "0.9"
}
  • 첫 번째 시나리오: RuntimeException 발생 시
    • API를 호출하면 즉시 예외가 발생하고, 재시도 후에도 실패하여 fallback 메서드가 호출됩니다.
    • 로그를 확인하면, getBuildInfo 메서드가 3번 호출되고, 마지막으로 getBuildInfoFallback이 호출됩니다.
Invoked getBuildInfo method
Invoked getBuildInfo method
Invoked getBuildInfo method
Invoked getBuildInfoFallback method due to: Simulated Exception

6. Circuit Breaker와의 상호작용

만약 Circuit Breaker가 함께 사용된다면, Timeout 설정에 따라 Retry Pattern이 영향을 받을 수 있습니다. 기본적으로 Circuit Breaker는 특정 시간 내에 응답이 없으면 바로 fallback 메서드를 호출합니다. 이 경우 Retry 설정이 무시될 수 있습니다.

6.1 Circuit Breaker Timeout 설정

Circuit Breaker의 기본 Timeout 설정을 변경하여 Retry Pattern이 제대로 작동하도록 할 수 있습니다.

@Bean
public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
    return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
        .timeLimiterConfig(TimeLimiterConfig.custom()
            .timeoutDuration(Duration.ofSeconds(4)) // Timeout을 4초로 설정
            .build())
        .circuitBreakerConfig(CircuitBreakerConfig.ofDefaults())
        .build());
}

7. 요약

이번 강의에서는 AccountsController에 Retry Pattern을 구현하고, 이 패턴이 제대로 작동하는지 확인하기 위해 여러 가지 설정을 추가했습니다. 또한 Circuit Breaker와 Retry Pattern이 어떻게 상호작용하는지에 대해서도 다루었습니다.

Retry Pattern을 통해 네트워크 장애와 같은 일시적인 문제를 처리할 수 있으며, Circuit Breaker와 함께 사용하여 마이크로서비스의 안정성을 더욱 강화할 수 있습니다.

8. 최종 코드

@RestController
public class AccountsController {

    private static final Logger logger = LoggerFactory.getLogger(AccountsController.class);

    @GetMapping("/build-info")
    @Retry(name = "getBuildInfo", fallbackMethod = "getBuildInfoFallback")
    public String getBuildInfo() {
        logger.debug("Invoked getBuildInfo method");
        throw new NullPointerException("Simulated Exception");
    }

    public String getBuildInfoFallback(Throwable t) {
        logger.debug("Invoked getBuildInfoFallback method due to: " + t.getMessage());
        return "0.9";
    }
}

이 강의를 통해 Retry Pattern을 개별 마이크로서비스에 적용하는 방법을 배웠으며, 이를 통해 마이크로서비스의 신뢰성을 높일 수 있었습니다. 다음 강의에서도 중요한 패턴들을 다룰 예정이니 기대해 주세요.

profile
무슨 생각하며 사니

0개의 댓글