Hystrix란
Netflix에서 Circuit Breaker Pattern을 구현한 라이브러리이다. Micro Service Architecture에서 장애 전파 방지를 할 수 있다.
Circuit Breaker Pattern
![]() |
|---|
| 출처 : https://martinfowler.com/bliki/images/circuitBreaker |
장애 연쇄
위 그림에서 supplier 서버에 장애가 생겨 항상 Timeout이 발생하는 경우, supplier 서버를 호출한 client 서버는 Timeout이 발생할 때까지 응답이 밀리게 된다. 응답이 밀리는 동안 요청이 계속 쌓여 결국 client 서버까지 요청이 과하게 밀려 장애가 발생할 수 있다.
이러한 상황이 발생하지 않도록 circuit breaker를 두어 장애 전파를 막을 수 있다.
![]() |
|---|
| 출처 : https://cloud.spring.io/spring-cloud-netflix/multi/multi__circuit_breaker_hystrix_clients.html |
Hystrix Flow Chart
![]() |
|---|
| 출처 : https://github.com/Netflix/Hystrix/wiki/How-it-Works |
HystrixCommand,HystrixObservableCommand객체 생성- Command 실행
- 캐시 여부 확인
- 회로 상태 확인
- 사용가능한 Thread Pool/Queue/Semaphore가 있는지 확인
HystrixObservableCommand.construc(), 혹은HystrixCommand.run()실행- 회로 상태 연산(Calculate circuit health)
- fallback 실행
- 응답 반환
Hystrix Circuit Breaker 구현
![]() |
|---|
| 출처 : https://github.com/Netflix/Hystrix/wiki/How-it-Works |
- circuit health check를 위한 최소한의 요청이 있을 때(
HystrixCommandProperties.circuitBreakerRequestVolumeThreshold()) - 그리고, 지정한 오류율을 초과했을 때(
HystrixCommandProperties.circuitBreakerErrorThresholdPercentage()) - 회로의 상태를
CLOSED에서OPEN으로 변경 - 회로가 열린 동안, 모든 요청에 대해서 fallback method을 바로 실행
- 일정 시간이 지난 후(
HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds()), 하나의 요청을 원래 method로 실행(HALF OPEN). 이 요청이 실패한다면OPEN으로 두고, 이 요청이 성공한다면CLOSED로 상태를 변경. 다시 1번으로 돌아감.
기본 설정
metrics.rollingStats.timeInMilliseconds: 오류 감시 시간, 기본값 10초circuitBreaker.requestVolumeThreshold: 감시 시간 내 요청 수, 기본값 20circuitBreaker.errorThresholdPercentage: 요청 대비 오류율, 기본값 50
기본 설정을 풀어서 설명하면 다음과 같다
감시시간 내(30초)에, 20번 이상의 요청이 있었고, 그 중에서 오류율이 50% 이상일 때 Circuit Breaker가 작동한다(circuit open)
감시 시간 내에 요청이 반드시 20번 이상이 있어야 회로가 열림. 30초 동안 요청이 19번이었고 모두 실패했어도 Circuit Breaker는 작동하지 않는다
예제
dependencies
1 | dependencyManagement { |
사용
1 |
|
StoreIntegration.getStores()가 실패하거나 회로가 열렸을 시에는.defaultStores가 실행된다.
설정
application.yml로 설정예시
1 | hystrix: |
java 설정예시
1 | class UserResource { |
설정 참고:
https://github.com/Netflix/Hystrix/wiki/Configuration#execution.isolation.strategy
실사용례
Micro Service Architecture에서 하나의 게시판을 보여주는 예제(게시글, 댓글, 추천 게시글 API를 호출)
예제는 spring 4.3.x + reactor로 작성했다.
서비스
1 | 4j |
CommentClient.java
1 | public class CommentClient { |
- 여러 서비스를 호출하면서도, 하위 서비스의 장애가 client로 노출되지 않고, 성공한 서비스 응답들은 모두 client로 줄 수 있음
Isolation
bulkhead pattern를 채용하여 종속성(dependency)을 분리하며, 각각에 대한 접근을 제한했다.
![]() |
|---|
| 출처 : https://github.com/Netflix/Hystrix/wiki/How-it-Works |
Threads & ThreadPool
호출 thread와 별도의 thread(ex. Tomcat thread pool)에서 동작한다.
![]() |
|---|
| 출처 : https://github.com/Netflix/Hystrix/wiki/How-it-Works |
ThreadPool을 사용하지 않아도 되는 경우
- 네트워크 connection/read timeout, retry 옵션을 사용하여 매우 빨리 실패하거나
- client가 항상 정상동작한다는 신뢰가 있는 경우
즉, 그냥 ThreadPool을 사용하자
Netflix에서 각각의 Thread pool을 사용하여 의존성 격리를 구성한 이유
- 결론부터 먼저 말하자면, Thread를 나누어 다른 Thread에 접근하기 어렵도록 종속성을 원천차단한다.
- application은 수없이 많은 팀의, 수없이 많은 back-end service 를 수없이 많이 호출한다
- 각 service는 client library를 가지고 있다
- client library는 항상 바뀐다
- client library는 새로운 네트워크를 호출할 수도 있고, retry, parsing, caching 등의 logic을 가지며
blackbox취급된다
![]() |
|---|
| 출처 : https://github.com/Netflix/Hystrix/wiki/How-it-Works |
Thread Pool 사용상 이점
- application이 client library로부터 보호된다
- 덕분에 새 client library를 추가할 때의 risk를 낮출 수 있다, 장애는 격리된 thread에서 발생한다
Thread Pool 사용상 단점
- queueing, scheduling, context switching 등의 오버 헤드 발생가 발생된다(Netflix에서는 이를 사소한 정도로 간주)
Thread 비용
- Hystrix는 자식 thread에서
construct(),run()을 실행할 때, 부모 thread에서 총 종단 시간을 측정하여 overhead를 계산한다. - Netflix에서는 10억 건 이상의 Hystrix Command를 실행하며, 각 API 인스턴스마다 5-20개의 thread를 가지고 있는 thread pool을 40+개를 설정한다.(대부분의 thread pool 내의 thread 개수는 10개)
ThreadLocal
기본적으로 @HytrixCommand는 다른 Thread로 동작을 하기 때문에, ThreadLocal이나 spring에서 지원해주는 @RequestScope, @SessionScope 빈에 접근할 수 없다. 필요한 경우 execution.isolation.strategy: SEMAPHORE로 변경하여 현재 Thread에서 연산을 실행하게 할 수 있다.
Spring Security를 사용하는 경우, hystrix.shareSecurityContext=true로 설정해서 SecurityContext를 공유할 수 있다.
THREAD 동작 방식의 경우에는 Thread-pool내의 Thread 갯수 만큼, SEMAPHORE 동작 방식의 경우에는 semaphore count 만큼 요청을 수행할 수 있다
execution.isolation.semaphore.maxConcurrentRequests
Semaphore
Thread pool을 사용하는 대신, Semaphore(counter)를 사용하여 종속성에 대한 동시 호출 수를 제한할 수 있다. 따라서 Thread를 사용하지 않고 부하를 분한하지만, timeout과 격리가 느슨해지는 단점이 있다 위에서 ThreadPool을 사용하지 않아도 되는 경우에서 설명한 것과 같이 back-end server를 신뢰할 수 있다면 사용해도 괜찮다
HystrixCommand와 HystrixObservableCommand는 두 곳에서 semaphore를 지원한다
- Execution:
execution.isolation.strategy=SEMAPHORE로 설정이 되어 있으면, 해당 command를 실행할 수 있는 부모 스레스 수를 제한 - Fallback 검색






