Milk's development review

Netflix Hystrix 본문

Framework/Spring

Netflix Hystrix

YooMilk 2021. 2. 18. 12:08
반응형

MSA 서비스가 늘어나면서 개발자는 각 모듈간 장애 전파, 연쇄에 대한 처리에 좀 더 신중을 기울여야합니다.

오늘은 API Consumer입장에서 fail over관리를 효율적이고 일관되게 할 수 있도록 도와주는 Hystrix에 대해서 간단히 정리해보겠습니다.

Hystrix란


이미 알고있는 분들도 계시겠지만, Hystrix는 Netflix에서 Circuit Breaker Pattern을 구현한 라이브러리 입니다.
MSA에서 분산된 서비스간 통신이 원활하지 않은 경우에 각 서비스가 장애내성과 지연내성을 갖게하도록 도와줍니다.

사용해보기


- Supplier

Supplier는 아래와 같이 단순한 String을 return해주는 API를 작성했습니다.

- Consumer

Hystrix는 스프링에서 스프링 친화적으로 이미 랩핑을 해 놓았습니다.
API Consumer에 아래처럼 dependency를 추가해줍니다. (Spring boot 환경)

<dependency>
     <groupId>org.springframework.cloud</groupId>
     <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>

SpringBootApplication가 설정 된 클래스에 @EnableCircuitBreaker 애너테이션을 달아서 Circuit Breaker를 활성화 시킵니다.

이제 Hystrix를 사용할 준비가 다 끝났습니다. 적용하고 싶은 메서드에 @HystrixCommand 애너테이션을 달고 전략에 맞는 설정값을 주면 됩니다.

HystrinxCommand에는 fail over를 위한 configuration이 있는데요, 대표적인 configuration들을 하나씩 살펴보겠습니다.

  • commandKey : 서킷을 오픈할 때 통계정보가 수집되는 key값입니다. 입력하지 않을경우 디폴트는 메서드명입니다.
    가령 서로다른 API를 호출하는 두 메서드에 @HystrixCommand 애너테이션을 등록하고 같은 commandKey값을 설정해 둔다면, 두 메서드는 같은 통계정보를 공유합니다.
    통계정보를 이용해 Hystrix는 서킷을 open할지 half-open할지 close할지 판단합니다. 통계정보에 관련된 설정값은 아래에서 다룹니다.
  • fallbackMethod : Hystrix 메서드가 실패했을때 실행되는 메서드입니다.
    여기서 실패는 메서드 내부에서 Exception이 발생할 경우, 서킷이 오픈된 경우, 기타 다른 실패와 관련된 설정값에 상태가 부합하는 경우를 의미합니다.
  • execution.isolation.thread.timeoutInMilliseconds : Hystrix가 적용된 메서드의 타임아웃을 지정합니다. 이 시간내에 메서드가 완료되지 못하면 서킷의 상태와 상관없이 fallback메서드가 호출됩니다.

아래 설정값들은 서킷 오픈과 관련된 설정으로 예제 문장을 통해서 설명하겠습니다.
"10초간 20번 이상 호출되었고 그중 50%이상이 실패면 서킷을 1분간 오픈한다."
각 설정에 해당하는 부분에 색상처리를 해두었습니다.

 

  • metrics.rollingStats.timeInMilliseconds : "10초간 20번 이상 호출되었고 그중 50%이상이 실패면 서킷을 1분간 오픈한다."
  • circuitBreaker.errorThresholdPercentage : "10초간 20번 이상 호출되었고 그중 50%이상이 실패면 서킷을 1분간 오픈한다."
  • circuitBreaker.requestVolumeThreshold : "10초간 20번 이상 호출되었고 그중 50%이상이 실패면 서킷을 1분간 오픈한다."
  • circuitBreaker.sleepWindowInMilliseconds : "10초간 20번 이상 호출되었고 그중 50%이상이 실패면 서킷을 1분간 오픈한다."

마지막 설정값인 threadPoolProperties를 설명하기전에 Hystrix의 동작방식에 대해서 먼저 짚고 넘어가겠습니다.
Hystrix는 Thread방식과 Semaphore(또는 counter)방식으로 나뉩니다.
Thread 방식에서는 서비스 호출이 별도의 스레드에서 수행됩니다. 즉, 다른 스레드풀의 스레드와 격리가 되어 종속성을 원천차단합니다.
덕분에 client library의 장애는 격리된 thread에서 발생합니다.
하지만 별도의 Thread pool을 관리함에따라 오는 overhead도 있는데요, Netflix에서는 이를 사소한 정도로 간주하고 있고, Hystrix Configuration 문서에서도 Thread 방식을 권장하고 Semaphore를 써야하는 경우는 '유일'하다고 말하고 있습니다.
Semaphore를 써야 하는 유일한 경우는 '호출량이 너무 많아서 분리된 스레드의 사용이 주는 오버헤드가 큰 경우'라고 합니다.
이 글에서는 Semaphore방식에 대해서는 이 이상 다루지 않겠습니다.

다시 돌아와서 마지막 configuration을 살펴보겠습니다.

 

  • threadPoolProperties - coreSize : Hystrix가 Thread방식을 사용할때 coreSIze를 지정합니다.

이외에도 Thread pool관리에 따른 다양한 설정값들이 존재합니다.

Run Example


- Exception Case

Supplier API에서 Exception을 발생시키도록 해두고 Consumer에서 Supplier API를 호출합니다.

결과 페이지

Consumer가 API를 호출하면 Supplier가 Exception을 throw하고 이는 Consumer까지 전파됩니다.
따라서 fallback상황에 부합하므로 fallback메서드가 호출됩니다.
만약 restTemplate에 read, socket timeout 설정에 따라서 timeout이 발생할 경우, 혹은 기타 다른 Exception이 발생한 경우에도 동일하게 동작합니다.

- execution.isolation.thread.timeoutInMilliseconds Case

Consumer의 execution.isolation.thread.timeoutInMilliseconds설정은 500ms로 되어있습니다.
이때 Supplier API 내부 로직에서 Thread.sleep(1000)을 코드에 추가합니다.

결과 페이지

위 상황에서는 별다른 Exception이 발생하지 않았지만 Hystrix의 Thread timeout 조건에 부합하므로 fallback메서드가 호출됩니다.
그렇다면 Supplier는 어떻게 반응할까요? Hystrix는 Consumer에만 적용되어 있기 때문에 Supplier에는 아무런 영향이 없습니다.
따라서 Supplier는 정상적으로 로직이 수행됩니다.

- Circuit Open/Half-Open Case

Supplier API에서 Exception을 발생시키도록 해두고 Consumer Hystrix Circuit옵션은 아래와 같습니다.
"5초간 5번 이상 호출되었고 그중 10%이상이 실패면 서킷을 10초간 오픈한다."

위에 언급했던 commandKey가 되는 "supplier-api"에 Hystrix는 통계정보를 계속 기록합니다.
그리고 기록된 통계정보가 위의 Circuit Open 조건에 부합하면 Hystrix는 Circuit을 Open하게 됩니다.
한번 Open되면 circuitBreaker.sleepWindowInMilliseconds에 설정된 시간동안은(예제에서는 10초) 무조건 fallbackMethod만 수행합니다.
이후 10초가 지나면 Circuit은 Half-Open상태가 되며 그 다음 요청의 성공/실패 여부에 따라 Circuit Open/Close 여부를 판단하고 적용시킵니다.

마치며


앞에서 다뤄본 설정 외에도 다양한 설정값들이 존재하며 상황에 맞추어 사용하면 외부 API의 장애/지연에 적절하게 대응할 수 있을 것 같습니다.
자세한 Hystrix work flow는 공식문서에 잘 정리되어있으니 그 부분을 참고하시면 될거 같습니다.
하지만 Hystrix는 꽤나 low-level library이며 단독으로 사용되는 경우는 비교적 적은 것 같습니다.
찾아본 바로는 REST기반 서비스 호출을 추상화 해주는 Feign라이브러리에 Hystrix를 입혀서 사용하는 경우가 꽤 많은거 같습니다.
연관된 주제로 Zuul(L7 application gateway)과 Ribbon(Client Side Load Balancing)도 사용하는 사례가 많은거 같구요.
Feign, Zuul, Ribbon도 정리가 되면 아주 매우 천천히 공유하도록 하겠습니다.

틀린 부분의 수정이나 덧붙여주실 내용이 있으면 언제든지 환영입니다. 감사합니다.

반응형
Comments