본문 바로가기
프로그래밍/Spring Cloud

[MSA] Spring Cloud Feign - With Hystrix

by 사바라다 2020. 10. 10.

안녕하세요. 오늘은 Spring Cloud Feign의 마지막 시간입니다. 오늘 알아볼 내용은 Feign에서 Hystrix와 연동은 어떻게 이루어지고 어떻게 동작하는지, 그리고 이를 실습해보는 시간을 가져보도록하겠습니다. Hystrix에 대한 개념이 없으시거나 부족하신 분들은 제가 포스팅한 예전 포스트가 있으므로 참조해주시면 좋을 것 같습니다. [MSA] Spring Cloud Hystrix - 개념편

의존성

저는 현재 시점의 Spring Cloud의 최신버전인 Hoxton.SR8를 사용하고 있습니다. 해당 mavenBom으로 OpenFeign의 의존성을 가져오면 최신버전인 2.2.5.RELEASE를 사용할 수 있습니니다.있습니다. 다른 많은 포스팅을 보시면 hystrix의 의존성을 추가해야한다고 합니다. 하지만 해당버전은 Hystrix를 사용하기 위해서 별도로 Hystrix의 의존성을 추가할 필요가없습니다. 왜냐하면 openFeign 내부에 feign-hystrix를 내장하고 있기 때문입니다.

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR8"
    }
}

dependencies {
    implementation "org.springframework.cloud:spring-cloud-starter-openfeign"

}

설정

hystrix를 사용하는 방법으로는 전체적으로 설정해주는 global 설정과 CustomFeignConfiguration으로 FeignClient마다 별도로 설정하는 방법이 존재합니다. 각각 설정하는 방법에 대해서 알아보겠습니다.

Global 설정

Global 설정에는 2가지 방법이 있습니다. @Configuration을 이용하여 Feign.Builder를 Hystrix를 사용할 수 있도록 설정하거나 yml을 이용하는 방법입니다.

먼저 yml을 통해 진행해보겠습니다. 아래와 같이 지정하면 feign의 hytrix를 사용할 수 있게됩니다.

feign:
  hystrix:
    enabled: true

두번째는 Java의 설정파일을 이용하는 방법입니다. Feign에 사용되는 Builder를 HystrixFeign로 빈을 등록시켜주는 것입니다. 위와 아래는 동일하게 Hystrix를 사용할 수 있도록 하는 결과를 가져옵니다.

@Configuration
public class HttpConfiguration {

  @Bean
  Feign.Builder feignBuilder() {
    return HystrixFeign.builder();
  }
}

구체적인 설정은 좀 더 뒤에서 보도록 하겠습니다.

Local 설정

@FeignClient(name = "azureClient", url = "${external.bing.url}", configuration = AzureHttpConfiguration.class)
public interface AzureClient {

  @GetMapping("hello")
  String localDate(
      @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate from,
      @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate to);
}

위의 FeignClient에만 별도로 적용하고 싶을 수 있습니다. 이럴 경우 @FeignClient의 configuration 속성으로 Configuration Class를 넣어주고 해당 Class에 아래와 같이 설정해줍니다.

public class AzureHttpConfiguration {

  @Bean
  Feign.Builder feignBuilder() {
    return HystrixFeign.builder();
  }
}

Fallback

Feign에서 Hystrix설정을 했다면 이제 Fallback 메서드를 정의하고 에러에 대해서 fallback 메서드가 제대로 실행되는지 확인해보도록 하겠습니다.

아래는 fallback을 사용하는 FeignClient와 FallbackClass를 구현한 것입니다. AzureClient의 localDate 메서드를 호출해서 실패한다면 AzureClientFallback의 localDate 메서드가 실행되게 되는 구조입니다.

@FeignClient(name = "azureClient", url = "${external.bing.url}", configuration = AzureHttpConfiguration.class, fallback = AzureClientFallback.class)
public interface AzureClient {

  @GetMapping("hello")
  String localDate(
      @RequestParam("startDate") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate from,
      @RequestParam("endDate") @DateTimeFormat(pattern = "yyyy-MM-dd") LocalDate to);
}

@Component
public class AzureClientFallback implements AzureClient {

    @Override
    public String localDate(LocalDate from, LocalDate to) {
      log.info("localDate fallback");
      return null;
    }
  }

FallbackFactory

이 구조에서는 아쉽지만 어떤 원인으로 에러가 발생했는지 추적하는게 쉽지 않습니다. 왜냐하면 Throwable을 파라미터로 주지않기 때문에 fallback에서 로깅을 할 수 없기 때문입니다. Throwable을 fallback에서 사용하기 위해서는 fallbackFactory를 사용해야합니다. 사용방법은 아래와 같습니다.

@FeignClient의 fallback 속성은 fallbackFactory 속성으로 바꿉니다. 그리고 아래 설정한 FallbackFactory를 설정합니다. FallbackFactory에서는 create 메서드를 오바라이드하게 됩니다. 해당 오버라이드 메서드에서 Throwable의 처리를 할 수 있게됩니다. 실행순서는 먼저 create 메서드 그리고 실제 fallback 메서드를 사용하는 순서를 가지게됩니다.

@FeignClient(name = "azureClient", url = "${external.bing.url}",
    configuration = AzureHttpConfiguration.class, fallbackFactory = AzureClientFallbackFactory.class)
public interface AzureClient {
    ...
}

@Slf4j
@Component
public class AzureClientFallbackFactory implements FallbackFactory<AzureClient> {

  private final AzureClientFallback azureClientFallback;

  public AzureClientFallbackFactory() {
    this.azureClientFallback = new AzureClientFallback();
  }

  @Override
  public AzureClient create(Throwable cause) {
    log.info("[Azure] error occurred, {}", cause.getMessage());
    return azureClientFallback;
  }

  public class AzureClientFallback implements AzureClient {

    @Override
    public String localDate(LocalDate from, LocalDate to) {
      log.info("localDate fallback");
      return null;
    }
  }
}

Hystrix Custom 설정

추가로 Hystrix의 커스터마이징을 알아보도록 하겠습니다. Hystrix의 기본ㅇ느 서킷브레이크를 오픈하여 장애 전파 방지를 가능하게 합니다. hystrix는 기준시간 동안 요청값을 검사하여 그중 에러 비율이 어느정도를 넘으면 서킷을 오픈하여 일정 시간동안 fallback 처리한다.를 기본으로합니다. 이런 값을 설정하는 법을 알아보겠습니다.

@Bean
Feign.Builder feignBuilder() {
SetterFactory setterFactory = (target, method) -> HystrixCommand.Setter.withGroupKey(HystrixCommandGroupKey.Factory.asKey(target.name()))
    .andCommandKey(HystrixCommandKey.Factory.asKey(Feign.configKey(target.type(), method)))
    // 위는 groupKey와 commandKey 설정
    // 아래는 properties 설정
    .andCommandPropertiesDefaults(HystrixCommandProperties.defaultSetter()
        .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)
        .withMetricsRollingStatisticalWindowInMilliseconds(10000) // 기준시간
        .withCircuitBreakerSleepWindowInMilliseconds(3000) // 서킷 열려있는 시간
        .withCircuitBreakerErrorThresholdPercentage(50)) // 에러 비율 기준 퍼센트
        .withCircuitBreakerRequestVolumeThreshold(5)); // 최소 호출 횟수
return HystrixFeign.builder().setterFactory(setterFactory);
}

마무리

오늘은 이렇게 Spring Cloud Feign의 마지막 시간으로 Hystrix와 Feign을 함께 사용하는 방법에 대해 알아보는 시간을 가져보았습니다. 궁금하신 점이나 이상하다 싶으신 점이 있으면 덧글 남겨주세요. 함께고민하면 좋겠습니다.

감사합니다.

참조

spinrg_cloud_openfeign_reference

https://brunch.co.kr/@springboot/262

댓글