서론
MSA 기반을 둔 Application은 클라이언트 회복성이 고려되어야하고,
핵심적인 클라이언트 회복성 패턴은 주로 회로 차단(Circuit breaker), 폴백(fall back), 벌크 헤드(bulk head) 이다.
Circuit breaker Pattern은 느리게 실행되고, 성능이 저하된 시스템 호출을 종료해 빨리 실패시키고 자원 고갈을 방지한다.
Fall back Pattern은 개발자가 원격 서비스 호출이 실패하거나 호출에 대한 회로 차단기가 실패할때 대체할 코드 경로를 정의할 수있다.
Bulk head Pattern은 원격 호출을 서로 격리하고 원격 서비스 호출을 자체 스레드 풀로 분리한다.
즉, 일련의 서비스 호출이 실패할 때 Application container의 모든 자원이 고갈되어서는 안된다.
본론
Histrix은 Netflix에서 Circuit breaker, Fall back, Bulk head Pattern을 구현한 라이브러리이다.
현재 MSA를 지향하고 있는데, MSA(Micro Service Architecture)에서 쓰는 장애 전파 방지 전략 중 하나라고 이해하면 된다.
Histrix 이해
기본적으로 Histrix는 부모 thread의 context를 Histrix 명령이 관리하는 thread에 전파하지 않는다.
실행순서 | 내용 | |
1 |
* circuit health check을 위한 최소 요청(HystrixCommandProperties.circuitBreakerRequestVolumeThreshold())이 있는 경우 |
|
2 | 회로의 상태를 CLOSED에서 OPEN으로 변경 |
|
3 | 회로가 열린 동안, 모든 요청에 대해서 fallback method을 바로 실행 |
|
4 | 일정 시간(HystrixCommandProperties.circuitBreakerSleepWindowInMilliseconds())이 지난 후 하나의 요청을 원래 method로 실행(HALF OPEN) |
|
5 | 이 요청이 실패하면 OPEN로 상태 변경 ⇢ 1번부터 실행 | 이 요청이 성공하면 CLOSED로 상태 변경 ⇢ 3번부터 실행 |
이때, Hystrix은 @HystrixCommand 개체로 보호되는 것을 뜻하며 THREAD 격리 수준을 사용하고 있다고 가정한다.
참고로 Histrix는 THREAD와 SEMAPHORE 격리 모델을 지원한다.
SEMAPORE 모델은 Histrix 호출을 위해 별도의 스레드를 사용하지 않고,
이 호출을 중단할때 서비스가 예상하지 않는 동작도 유발할 수 있다.
Histrix를 사용하면 사용자가 정의한 HystrixConcurrencyStrategy를 구현해
부모 Thread Context를 Histrix가 관리하는 Thread에 주입할 수 있다.
Histrix 사용 방법
예를 들어, REST 기반 환경에서 종종 서비스를 운영하는데 Context 관련 정보를 서비스 호출로 전달하려고 한다.
이때 REST/HTTP 헤더에 상관관계 ID나 모든 하위 서비스 호출에 전파 할 수 있다.
그러면 상관관계 ID를 사용하면 한 트랜잭션 내 여러 서비스 호출을 추적할 수 있는 고유한 식별자(ID)를 갖게 된다.
이 값을 모든 서비스 호출에 사용하게 하려면 스프링 필터(Spring Filter) 클래스를 사용해 REST 서비스에 대한 모든 호출을 가로채고,
유입되는 HTTP 요청에서 Context 정보를 추출해 사용자가 정의한 Context 객체에 저장할 수 있다.
(1) HystrixCommandHandler.java : HystrixEventNotifier를 통해 Hystrix Event에 대해 알림 받을 수 있음
(★ Hystrix Event 은 하단 [참고] 내용에 좀 더 상세히 표기했음)
import com.netflix.hystrix.HystrixCommandKey;
import com.netflix.hystrix.HystrixEventType;
import com.netflix.hystrix.strategy.eventnotifier.HystrixEventNotifier;
public class HystrixCommandHandler extends HystrixEventNotifier {
@Override
public void markEvent(HystrixEventType eventType, HystrixCommandKey commandKey) {
System.out.printf("-->Event, type=%s, Key=%s%n", eventType, commandKey);
if (eventType.equals(HystrixEventType.FALLBACK_SUCCESS)) {
this.sendFailMessage(eventType);
}
}
…
}
(2) Service.java : @HystrixCommand를 통해 Circuit breaker, Fall back 구현
@Service
public class Service {
@HystrixCommand(fallbackMethod = "fallBackDoSomething")
public void doSomething() {
System.out.println("Test Logic");
}
public void fallBackDoSomething(Throwable throwable) {
System.out.printf("exception=%s%n", throwable);
}
}
(3) Application.java : @EnableCircuitBreaker 를 통해 Application에서 Hystrix를 사용, HystrixPlugins으로 HystrixCommandHandler.java 를 bean 등록
import com.netflix.hystrix.strategy.HystrixPlugins;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.context.ConfigurableApplicationContext;
@SpringBootApplication
@EnableCircuitBreaker
public class Application {
public static void main(String[] args) {
HystrixPlugins.getInstance().registerEventNotifier(new HystrixCommandHandler());
SpringApplication.run(Application.class, args);
}
}
[ 참고 ]
HystrixEventType
Type명 |
설명 |
내용 |
SUCCESS |
성공 |
HTTP 200 |
FAILURE |
오류 |
Request 실패 |
FALLBACK_SUCCESS |
FallBack 성공 |
설정한 Hystrix(@HystrixCommand)에 의해 FallBack 함수 실행 성공 |
FALLBACK_FAILURE |
FallBack 실패 |
설정한 Hystrix(@HystrixCommand)에 의해 FallBack 함수 실행 실패 |
EXCEPTION_THROWN |
Exception 처리 |
Fall back 함수 실행 실패로 Exception 처리 |
SHORT_CIRCUITED |
CircuitBreaker 실행 |
Fall back 함수가 실행되며 CircuitBreaker 실행 • Fall back 성공되어야 실행됨 • HTTP 200으로 들어와도 Fall back 함수 실행됨 |
[관련 서적] books.google.co.kr/books?id=VACDDwAAQBAJ
[관련 내용] github.com/Netflix/Hystrix
[Histrix 상세 설정] github.com/Netflix/Hystrix/wiki/configuration#command-properties