서킷 브레이커 fallbackMethod 구현 정리

CosmoNumb·2024년 8월 3일
0

MSA

목록 보기
4/13

현재 테스트성으로 구현한 프로젝트는 유레카를 사용하지 않고, 상품을 조회하는 프로젝트를 가정하여 단순한 fallbackMethod 매커니즘을 테스트한 결과 페이지 입니다.

  1. 상품 아이디 111을 호출하면 에러를 발생시켜 fallbackMethod를 실행하는 것을 확인합니다.
    (fallbackMethod 실행된 뒤 일정시간 이후 다시 fallbackMethod가 해제되는 것을 볼 수 있습니다.)

  1. actuator/prometheus 로그 조회

서킷 브레이커가 localhost:19090에서 실행되는 흐름은 다음과 같습니다:

1. 요청이 들어옴

사용자가 브라우저나 API 클라이언트를 통해 http://localhost:19090/product/111 URL로 요청을 보냅니다.

2. ProductController가 요청을 처리

Spring Boot 애플리케이션이 요청을 수신하고, 이 요청은 ProductControllergetProduct 메서드로 전달됩니다.

@RestController
@RequiredArgsConstructor
public class ProductController {

    private final ProductService productService;

    @GetMapping("/product/{id}")
    public Product getProduct(@PathVariable("id") String id) {
        return productService.getProductDetails(id);
    }
}

3. ProductService에서 비즈니스 로직 실행

ProductControllerProductServicegetProductDetails 메서드를 호출하여 해당 제품의 세부 정보를 가져오려고 합니다. 이 메서드는 @CircuitBreaker 애노테이션이 적용되어 있습니다.

@Service
@RequiredArgsConstructor
public class ProductService {

    private final Logger log = LoggerFactory.getLogger(getClass());
    private final CircuitBreakerRegistry circuitBreakerRegistry;

    @PostConstruct
    public void registerEventListener() {
        circuitBreakerRegistry.circuitBreaker("productService").getEventPublisher()
                .onStateTransition(event -> log.info("#######CircuitBreaker State Transition: {}", event))
                .onFailureRateExceeded(event -> log.info("#######CircuitBreaker Failure Rate Exceeded: {}", event))
                .onCallNotPermitted(event -> log.info("#######CircuitBreaker Call Not Permitted: {}", event))
                .onError(event -> log.info("#######CircuitBreaker Error: {}", event));
    }

    @CircuitBreaker(name = "productService", fallbackMethod = "fallbackGetProductDetails")
    public Product getProductDetails(String productId) {
        log.info("###Fetching product details for productId: {}", productId);
        if ("111".equals(productId)) {
            log.warn("###Received empty body for productId: {}", productId);
            throw new RuntimeException("Empty response body");
        }
        return new Product(productId, "Sample Product: " + productId);
    }

    public Product fallbackGetProductDetails(String productId, Throwable t) {
        log.error("####Fallback triggered for productId: {} due to: {}", productId, t.getMessage());
        try {
            log.info("####Fallback method started sleeping for 5 seconds");
            Thread.sleep(5000);
            log.info("####Fallback method finished sleeping");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("####Fallback method interrupted", e);
        }
        return new Product(productId, "Fallback Product");
    }
}

4. 서킷 브레이커 동작

  • 정상 동작: 입력된 productId111이 아닌 경우 정상적으로 제품 정보를 반환합니다.
  • 오류 발생: 입력된 productId111인 경우 RuntimeException을 발생시켜 오류를 기록합니다.

5. 서킷 브레이커 상태 변화

  • Closed 상태: 서킷 브레이커가 모든 요청을 허용하는 기본 상태입니다.
  • Open 상태: 오류가 일정 비율 이상 발생하면 서킷 브레이커가 열리고, 모든 요청이 차단됩니다.
  • Half-open 상태: 일정 시간 후 일부 요청을 허용하여 서비스가 정상화되었는지 확인합니다.

6. Fallback 메서드 호출

getProductDetails 메서드에서 예외가 발생하면 fallbackGetProductDetails 메서드가 호출됩니다. 이 메서드는 5초 동안 지연 시간을 둔 후 폴백 응답을 반환합니다.

public Product fallbackGetProductDetails(String productId, Throwable t) {
    log.error("####Fallback triggered for productId: {} due to: {}", productId, t.getMessage());
    try {
        log.info("####Fallback method started sleeping for 5 seconds");
        Thread.sleep(5000);
        log.info("####Fallback method finished sleeping");
    } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
        log.error("####Fallback method interrupted", e);
    }
    return new Product(productId, "Fallback Product");
}

7. 서킷 브레이커 설정 (application.yml)

application.yml 파일에서 서킷 브레이커 설정이 정의되어 있습니다.

spring:
  application:
    name: sample

server:
  port: 19090

resilience4j:
  circuitbreaker:
    configs:
      default:
        registerHealthIndicator: true
        slidingWindowType: COUNT_BASED
        slidingWindowSize: 5
        minimumNumberOfCalls: 5
        slowCallRateThreshold: 100
        slowCallDurationThreshold: 60000
        failureRateThreshold: 50
        permittedNumberOfCallsInHalfOpenState: 3
        waitDurationInOpenState: 5s  # 5초로 설정

management:
  endpoints:
    web:
      exposure:
        include: prometheus
  prometheus:
    metrics:
      export:
        enabled: true

요약

  1. 사용자가 http://localhost:19090/product/111로 요청을 보냄.
  2. ProductController가 요청을 받아 ProductServicegetProductDetails 메서드를 호출.
  3. productId111인 경우 예외 발생.
  4. 서킷 브레이커가 오류를 기록하고 Fallback 메서드 호출.
  5. Fallback 메서드에서 5초 지연 후 폴백 응답 반환.
  6. 서킷 브레이커는 설정된 정책에 따라 상태를 전환하고 요청을 관리.

Github 레파지토리

0개의 댓글