mm Home

Hystrix 본문

개발/기타

Hystrix

jess_m 2017. 8. 17. 19:12

Neflix 에서 만든 오픈소스.

사내에서 Hystrix를 사용하고 있는 프로젝트가 꽤 있길래 좀 살펴보았다.



Hystrix 란?


공식 페이지에 많은 설명이 쓰여있지만.. 그냥 가볍게 사용해본 개인적인 느낌으로는 

'분산 환경에서의 안정적인 서비스를 지원해주는 라이브러리'라고 생각한다.

그 안정적인 서비스를 지원해주는 기능으로 무엇이 있는지는 밑에 나열해볼 것이고... 추상적이지만 안정적인 서비스를 지원해주는 라이브러리가 어떤 느낌인지 예를 들어 설명해보겠다.



분산 환경에서 각 서비스별 의존성을 지니는 경우가 많다.

이를테면, 이벤트 서버에서 회원에 대한 조회를 할때 Membership 서버에 Request를 날리는 것과 같이 의존성이 있을 수 있다.


만약 멤버쉽 서버(외부 자원)의 응답이 늦어진다면, 이벤트 서버는 어떻게 될까?

스레드가 오래 살아있게 되고, 스레드가 계속적으로 생성될 것이다. Context switching 비용이 늘어나고, CPU 사용량도 올라간다. GC에서 해제되지 않는 메모리도 늘어난다. GC도 자주 일어날테고... 

상황이 악화되어 이벤트 서버의 유저 스레드 포화로 이어지고 실제 유저는 5XX에러를 받아볼 수도 있을 것이다.


물론 가정이지만.. 어쨋든 의존성있는 서비스의 실패가 다른 서비스에 전파될 수 있다.


여기서 Hystrix를 통해 Fallback, Circuit Breaker를 쉽게 구현하여 안정적인 서비스를 만들 수 있다. 부하를 줄이고 대기열을 생성하는 것이 아니라 Fail Fast 처리한다. 실패 상황에 대해 Fallback 지원. 그리고 Hystrix의 스레드 풀을 이용하여 유저 스레드와 외부자원 스레드를 분리(외부 자원은 isolation)할 수도 있고 실시간 모니터링도 지원해준다. 



Hystrix가 어떻게 동작하길래?


- 명령 패턴을 이용한다.

- 스레드 풀 이용. 포화 상태가 되면 대기열 대신 즉시 거부. 

- 성공, 실패, Time-out 등 실시간 Metric 측정

- 오류 퍼센트가 임계값을 초과한 경우에 대해 모든 요청 중지 가능 (Circuit Breaker)

- 요청 실패시 Fallback 수행.






Hystrix 공식 페이지에 있는 이미지이다. 사실 위의 사진을 보면 자세한 설명이 필요없을 정도로 Flow 차트가 잘 그려져있다.

그럼에도 좀 살펴보면...


1. HystrixCommand or HystrixObservableCommand 객체를 생성한다. 

2. 커맨드를 실행한다.

3. 캐시 여부를 확인한다.

4. circuit-breaker 발생 여부를 확인한다.

5. 스레드 풀/큐/세마포어가 가득찼는지 확인한다.

6. 실제 커맨드 메소드 실행 (run() 메소드 혹은 construct() 메소드)

7. 모니터링 요소 검사

8. 실패가 발생한 경우에 getFallback 실행 (circuit-breaker가 발생한 상황이나, construct() 혹은 run() 발생에서 실패가 된 경우)

9. 응답 반환



1. 커맨드 객체 생성

HystrixCommand, HystrixObservableCommand는 내부적으로 옵저버 패턴을 이용한다.  

HystrixCommand와 HystrixObservableCommand 차이는 blocking과 non-blocking의 차이이다. HystrixCommand는 toBlocking() 메소드를 호출하여 블록킹 연산을 수행한다. 논블록킹의 


2. 커맨드 실행

생성된 객체를 가지고 커맨드를 실행한다.

HystrixCommand 구현체에서는 execute()와 queue()를 사용할 수 있으며, 차이는 동기/비동기에 따라 나뉜다.

HystrixObservableCommand에서는 observe()와 toObervable()를 사용할 수 있으며, 역시 동기/비동기에 따라 나뉜다.

차트에서도 보이듯이 모든 실행 메소드를 실행해도 결국 toObservable() 메소드를 호출하게 된다.

toObservable() 메소드는 Observable 구현체를 구독하여 비동기적으로 실행하기 위함이다. 쉽게 설명하면 유저 스레드와 별개로 Command에 대한 스레드를 생성해서 비동기적으로 실행시켰고, 응답에 대해 Fallback 처리할 수 있도록 구독을 한 것이다. 이 과정에서 Observable을 RxJava로 사용하였다. (Observable - RxJava에 대해서 따로..)


3. 캐시 여부 확인

해당 커맨드에 캐시를 사용하고 있고, 캐시에 Response가 있다면 Observable 형태로 즉시 반환한다.


4. circuit-breaker발생 여부를 확인

커맨드를 실행할때, circuit이 열렸는지(or tripped) 확인을 하고, 열려있다면 커맨드를 실행하지 않고 즉시 getFallback()을 실행한다.


5. 스레드 풀/큐/세마포어가 가득찼는지 확인한다

커맨드의 스레드풀(or 세마포어)과 큐가 가득찼다면, 커맨드를 실행하지 않고 즉시 getFallback()을 실행한다.

circuit-breaker가 발생한 상황이나, construct() 혹은 run() 발생에서 실패가 된 경우에는 사용자가 구현한 getFallback() 또는 resumeWithFallback() 을 실행한다. 


6. 실제 커맨드 메소드 실행


7. 모니터링 요소 검사
성공, 실패, 거부, 타임아웃을 리포팅하여 통계 요소를 계산한다.


8. getFallback

커맨드의 예외 상황이 발생할 때마다 fallback으로 복구를 시도한다.





Isolation


Hystrix를 통해 실제 로직을 격리시켜 커맨드화 한다. 여기서 격리 방법이 2가지 존재한다.

Thread Pool 과 Semaphore 이다.


1. Thread Pool

커맨드가 쓰레드 풀을 이용하여 실행된다. Request 하나에 Thread 하나를 연결하여 실행이 된다. 따라서 Request와 커맨드가 다른 쓰레드에서 실행되므로 완전한 격리상태로 볼 수 있다. 세마포어를 꼭 이용해야하는 이유가 아니라면, Thread Pool을 이용하는 것을 권장하는 것 같다. 

쓰레드 하나당 커맨드를 진행하므로 Timeout을 보장할 수 있고, 비동기 프로그래밍을 할 수 있다.(rxJava - Observable)

다만 단점으로 오버헤드가 조금 있다는 점이다. 큐잉, 스케쥴링, 컨텍스트 스위칭 같은 동작에서 약간의 오버헤드가 발생한다. (오버헤드에 성능 저하 지표를 보고싶다면, 공식 홈페이지에서 제공하는 자료가 있으니 참고. response time에 대한 백분위로 90th Request 가 3ms 저하. 99th Request는 9ms 성능 저하가 있다고 함)


2. Semaphore

쓰레드를 Request 마다 할당하지 않는다. 몇 개의 쓰레드만 할당해놓고 Semaphore를 이용한 경쟁을 통해 부하를 분산시킨다. 동시 호출을 제한하여 의존성을 격리시킨 것이다. 따라서 완전한 격리를 했다고 보기 어렵다. (그냥 동시에 n건 이상의 요청을 수행하지 않도록 한 것임). Request마다 별개의 스레드를 사용하지 않으니 Timeout을 지원하지 못한다.

지연이 없거나 단지 부하 분산만을 위하는 경우, 혹은 클라이언트측에서 Request에 대하 보장을 할 수 있는 경우에 사용한다. 





hystrix 사용방법


커맨드 구현 방법은 2가지가 있다.

POJO 기반의 클래스를 어노테이션으로 구현하는 방식과, HystrixCommand를 상속하여 구현하는 방식이다.


POJO기반 어노테이션

 

HystrixCommand 상속


구현한 내용은 아래와 같이 모니터링할 수 있다. 

hystrix 대쉬보드에서 모니터링할 Stream 데이터를 뽑아주는 주소를 입력하면 된다. 

Spring boot를 이용한 기본 설정에서는 http://localhost:8080/hystrix 에 접속하여 http://localhost:8080/hystrix.stream 를 입력하면 된다.

여러대를 클러스터링하여 모니터링하기 위해서는 turbine을 사용하면 된다.



'개발 > 기타' 카테고리의 다른 글

Netty  (0) 2017.11.17
Reactive Programming  (0) 2017.11.10
HTTP 동작 과정  (0) 2017.10.26
OSI 7  (0) 2017.09.29
Comments