ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • Spring Cloud Circuit Breaker
    개발 일지/Cloud 2022. 6. 30. 14:59
    반응형

    안녕하세요.

     

    스프링 클라우드 관련 튜토리얼 페이지를 한글화 하고 있는 요즘입니다.

     

     

    이번 포스트에서는 서킷 브레이커 튜토리얼을 진행해 보려고 합니다.

    https://spring.io/guides/gs/cloud-circuit-breaker/

     

    Spring Cloud Circuit Breaker Guide

    this guide is designed to get you productive as quickly as possible and using the latest Spring project releases and techniques as recommended by the Spring team

    spring.io


    Spring Cloud Circuit Breaker를 사용해서 실패할 수 있는 메서드 호출에 대해 서킷 브레이커를 적용하는 튜토리얼입니다.

     

    서킷 브레이커 패턴을 사용하여 메서드 호출이 실패했을 때 기능을 적절히 저하시키는 마이크로 서비스 애플리케이션을 빌드해봅니다.

    서킷 브레이커를 활용하면 관련 서비스가 실패해도 마이크로 서비스가 계속 작동하도록 해서 오류가 연쇄적으로 발생하는 것을 방지하고, 실패한 서비스가 복구할 수 있는 시간을 제공합니다.

     

    1. 서버 설정

    "Bookstore" 서비스는 단 하나의 엔드포인트를 가집니다.

    "/recommended"로 접근할 수 있고, 추천 도서 목록을 String의 Mono로 리턴합니다.

     

    메인 클래스를 아래와 같이 수정합니다.

    package hello;
    
    import reactor.core.publisher.Mono;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    @RestController
    @SpringBootApplication
    public class BookstoreApplication {
    
      @RequestMapping(value = "/recommended")
      public Mono<String> readingList(){
        return Mono.just("Spring in Action (Manning), Cloud Native Java (O'Reilly), Learning Spring Boot (Packt)");
      }
    
      public static void main(String[] args) {
        SpringApplication.run(BookstoreApplication.class, args);
      }
    }

    @RestController 어노테이션은 BookstoreApplication을 컨트롤러 클래스로 표시하고, @RequestMapping 메소드는 @ResponseBody 기능을 포함합니다. 

    @RequestMapping의 리턴 값은 원래 형식에서 자동으로 적절하게 변환되어 response body에 작성됩니다.

     

    클라이언트 애플리케이션과 포트가 충돌되지 않도록 server.port 값을 지정해 줍니다.

    # /src/main/resources/application.properties
    
    server.port=8090

     

    2. 클라이언트 설정

    Reading 애플리케이션(클라이언트)은 Bookstore 애플리케이션의 Front-end가 됩니다.

    도석 목록은 클라이언트의 "/to-read"에서 확인할 수 있고, 목록은 Bookstore 서비스 애플리케이션에서 찾을 수 있습니다.

     

    package hello;
    
    import reactor.core.publisher.Mono;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.reactive.function.client.WebClient;
    
    @RestController
    @SpringBootApplication
    public class ReadingApplication {
    
      @RequestMapping("/to-read")
        public Mono<String> toRead() {
          return WebClient.builder().build()
          .get().uri("http://localhost:8090/recommended").retrieve()
          .bodyToMono(String.class);
      }
    
      public static void main(String[] args) {
        SpringApplication.run(ReadingApplication.class, args);
      }
    }

    Bookstore에서 목록을 가져오기 위해 스프링의 WebClient를 사용합니다.

    WebClient 는 Bootsotre 서비스의 URL에 HTTP GET 요청을 하고, 그 응답을  String의 Mono로 리턴합니다.

    (스프링에서 WebClient를 사용해서 RESTful 서비스를 만드는 것은 "Building a Reactive RESTful Web Service" 가이드를 참고합니다.)

     

    서버 포트는 8080으로 지정합니다.

    # /src/main/resources/application.properties
    
    server.port=8080

     

    이제 브라우저에서 클라이언트의 "/to-read" 엔드포인트에 접근하여 도서 목록을 조회할 수 있습니다.

     

    지금 구조는 Bookstore 서비스에서 응답을 받기 때문에 다음과 같은 상황에 직면할 수 있습니다,

    운영 환경에서 어떤 문제가 발생하거나 Reading 클라이언트가 Bookstore에 접근할 수 없으면, 도서 목록을 조회할 수 없고 HTTP 500 에러 메시지를 마주하게 됩니다.

     

    3. 서킷 브레이커 패턴 적용

    서킷 브레이커 패턴:

    메소드 호출을 서킷 브레이커로 감싸게 되면, Spring Cloud Circuit Breaker는 해당 메소드의 호출 실패를 감지합니다.

    호출 실패가 임계점까지 쌓이면 후속 호출이 자동으로 실패하도록 서킷을 개방합니다.

    해당 서킷이 열려있는 동안, Spring Cloud Circuit Breaker는 호출을 그 메소드로 리디렉션하고 지정된 대체 메소드로 전달합니다.

     

    Spring Cloud Circuit Breaker는 상당히 많은 구현체를 지원하는데, 여기서는 Resilence4j 구현체를 사용합니다.

     

    Spring Cloud Circuit Breaker는 "ReactiveCircuitBreakerFactory" 를 제공하여, 애플리케이션에 새로운 서킷 브레이커를 만들 수 있습니다.

    package hello;
    
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    import reactor.core.publisher.Mono;
    
    import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreaker;
    import org.springframework.cloud.client.circuitbreaker.ReactiveCircuitBreakerFactory;
    import org.springframework.stereotype.Service;
    import org.springframework.web.reactive.function.client.WebClient;
    
    @Service
    public class BookService {
    
      private static final Logger LOG = LoggerFactory.getLogger(BookService.class);
    
    
      private final WebClient webClient;
      private final ReactiveCircuitBreaker readingListCircuitBreaker;
    
      public BookService(ReactiveCircuitBreakerFactory circuitBreakerFactory) {
        this.webClient = WebClient.builder().baseUrl("http://localhost:8090").build();
        this.readingListCircuitBreaker = circuitBreakerFactory.create("recommended");
      }
    
      public Mono<String> readingList() {
        return readingListCircuitBreaker.run(webClient.get().uri("/recommended").retrieve().bodyToMono(String.class), throwable -> {
          LOG.warn("Error making request to book service", throwable);
          return Mono.just("Cloud Native Java (O'Reilly)");
        });
      }
    }

    "ReactiveCircuitBreakerFactory" 는 새로운 서킷 브레이커를 만들 수 있는 "create" 메서드를 가지고 있습니다.

    서킷 브레이커를 만들고 "run"으로 실행하면 됩니다.

     

    실행하면 Mono 또는 Flux와 추가 Function을 가질 수 있습니다.

    감시하고 있는 메소드(API 등)에서 문제가 발생하면 위에서 추가로 구성한 Function이 기능을 대체합니다.

     

    새로 추가한 서킷 브레이커는 아래와 같이 적용할 수 있습니다.

    package hello;
    
    import reactor.core.publisher.Mono;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.reactive.function.client.WebClient;
    
    @RestController
    @SpringBootApplication
    public class ReadingApplication {
    
      @Autowired
      private BookService bookService;
    
      @RequestMapping("/to-read")
      public Mono<String> toRead() {
        return bookService.readingList();
      }
    
      public static void main(String[] args) {
        SpringApplication.run(ReadingApplication.class, args);
      }
    }

     

    4. 테스트

    다음과 같이 테스트하여 서킷 브레이커가 잘 작동하는지 확인할 수 있습니다.

     

    먼저, Bookstore 서비스와 Reading 클라이언트를 실행하고 브라우저에서 "localhost:8080/to-read"로 접근하여 응답 결과를 확인합니다.

     

    다음으로 Bookstore 서비스를 중단하고 다시 확인해 봅니다.


    https://github.com/spring-guides/gs-cloud-circuit-breaker

     

    GitHub - spring-guides/gs-cloud-circuit-breaker: Spring Cloud Circuit Breaker Guide :: How to Use Spring Cloud Circuit Breaker

    Spring Cloud Circuit Breaker Guide :: How to Use Spring Cloud Circuit Breaker - GitHub - spring-guides/gs-cloud-circuit-breaker: Spring Cloud Circuit Breaker Guide :: How to Use Spring Cloud Circui...

    github.com

     

    반응형
Designed by Tistory.