Hystrix


- Hystrix는 Netflix에서 공개한 대부분의 OSS에서 범용적으로 사용되는 오픈소스 라이브러리이다.



Hystrix는 다음과 같은 특징을 따른다.


- 분산환경을 위한 Latencey and Fault Tolerance 시스템

- 복잡한 분산 시스템에서 cascading failure를 멈춤

- 실패에 대해 빠르고 급격한 회복

-  gracefully degrade와 fallback

- 거의 실시간으로 모니터링, 경고, 작동 제어가 가능하다.



Cascade Failure - 서비스간 장애 전파


대부분의 마이크로 서비스 아키텍쳐로 설계된 시스템에서 서비스 컴포넌트는 무수히 많이 존재하며, 서비스와 서비스 혹은 서비스와 게이트웨이 등 컴포넌트 별 호출은 일반적으로 REST-end-point를 가지기 때문에 Http 통신을 통해 서비스를 호출한다. 


그런데 만일 어떤 서비스 컴포넌트나 Database, 아니면 시스템이 다운 됐을 경우 의존적으로 연결된 각 서비스는 Cascade Failure(계단식 오류, 연속적 오류)를 맞이하게 된다.







출처: https://subscription.packtpub.com/book/application_development/9781788624398/8/ch08lvl1sec60/when-the-services-fail-hello-hystrix




그림을 보면 쉽게 이해 할 수 있는데 장애가 발생한 Y서비스에, A서비스와 연결된 end-point를 comsumer가 호출할 경우 ex) /Service-Y/Service-A, A서비스와 M서비스 또한 잠재적으로 장애가 연속적으로 발생할 가능성이 높다.


이와 같은 문제를 Circuit Breaker Pattern을 통해 도움을 받을 수 있다.




Circuit Breaker Pattern


Hystrix는  Circuit breaker 패턴을 자바 기반으로 오픈소스화한 라이브러리이다. 



출처: https://amandeepbatra.wordpress.com/2015/01/05/what-is-circuit-breaker-design-pattern/



- 만일 서비스가 정상적인 상황이라면, Client Request는 Remote Service를 호출하도록 by-pass한다.

- Database의 서비스가 장애가 발생했다면, 복구 될 때까지 Fallback 메세지와 함께 5xx response를 반환할 수 있다.






Hystrix Flow Chart



flow 차트는 위와 같은데, 아래의 코드를 통해 비교해보자

spring-cloud-starter-netflix-hystrix는 annotation 기반으로 간단하게 구성할 수 있다. Getting_Started

아래 코드는 spring-cloud-starter-netflix-hystrix가 아닌 webflux와 hystrix-javanica library를 추가해 각 단계별에 대해 분석하였다.


dependencies {
compile('com.netflix.hystrix:hystrix-javanica:1.5.10')

compile('org.springframework.boot:spring-boot-starter-webflux')

}



1. HystrixCommand나 HystrixObservableCommand Object를 생성한다.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 static class MessageCacheGetCommand extends HystrixObservableCommand<Object> {
 
        @Autowired
        private final StatefulRedisConnection<StringString> redisConnection;
        private String id;
 
        private static Setter setter = Setter
                .withGroupKey(HystrixCommandGroupKey.Factory.asKey(MessageCacheGetCommand.class.getSimpleName()))
                .andCommandKey(HystrixCommandKey.Factory.asKey(MessageCacheGetCommand.class.getSimpleName()))
                .andCommandPropertiesDefaults(
                        HystrixCommandProperties.Setter()
                                .withExecutionIsolationStrategy(HystrixCommandProperties.ExecutionIsolationStrategy.SEMAPHORE)  // semaphore strategy
                                .withExecutionIsolationSemaphoreMaxConcurrentRequests(5// failure 5 requsts, circuit on.
                                .withExecutionTimeoutEnabled(true)
                                .withExecutionTimeoutInMilliseconds(100)
  );


 
cs





2. execute(sync), queue(async), observe(hot observable), toObservable(cold observable) 중 선택하여 실행


1
2
3
4
 public Observable<Object> get(String id) {
        return new MessageCacheGetCommand(redisConnection, id).toObservable();
   }
 
cs




3. 캐쉬 응답이 있다면, Response를 수행한다.



4. Circuit이 Open되어 있으면 8) 단계로 넘어 간다.

1
2
3
4
5
if (HystrixCircuitBreaker.Factory.getInstance(HystrixCommandKey.Factory.asKey(MessageCacheGetCommand.class.getSimpleName())).allowRequest()) {
            redisConnection.sync().setex(id, expireTimeSeconds, value);
        } else {
            log.info("Cache update canceled, Circuit breaker opened!");
        }
cs


5. Thread Pool/Queue/Semaphore가 Full이면 8)로 넘어간다.

6. HystrixObservableCommand.construct() 또는 HystrixCommand.run()을 수행한다. 수행 중 실패하거나 Timeout이 초과되면 8) 단계로 아니면 9) 종료 단계로 간다.


1
2
3
4
5
6
7
8
9
10
11
 
        @Override
        protected Observable<Object> construct() {
            return redisConnection.reactive()
                    .get(id)
                    .defaultIfEmpty(null)
                    .map(value -> {
                        return value;
                    });
        }
 
cs



7. Circuit Health를 계산한다. Hystrix는 성공, 실패, Rejection 또는 Timeout 등의 정보를 Circuit Breaker에게 제공한다. Circuit Breaker는 이를 기반으로 Circuit을 열고 닫는다.

8. Fallback은 각 단계에서 실패, Timeout, Rejection 등이 발생할 때, 명시적인 핸들링을 할 수 있게하고 적절한 Response를 리턴할 수 있게한다.

1
2
3
4
   @Override
        protected Observable<Object> resumeWithFallback() {
            return Observable.empty();
        }
cs


9. 성공적으로 Response를 반환한다.







출처


https://github.com/Netflix/Hystrix/wiki/How-it-Works

https://medium.com/@goinhacker/hystrix-500452f4fae2

https://bcho.tistory.com/1247

https://supawer0728.github.io/2018/03/11/Spring-Cloud-Hystrix/

'Framework > Spring ' 카테고리의 다른 글

Spring AOP (1)  (0) 2019.08.02
Spring Cloud Netflix (3) - zuul  (0) 2019.06.06
Spring Cloud Netflix (1) - OverView  (0) 2019.02.10
Spring Websocket (Handler, STOMP, Reactive Websocket)  (6) 2019.02.10

+ Recent posts