운영 이슈 테스트를 위한 CS4SB (2/2)

안승섭·2023년 4월 23일
0

경험들

목록 보기
7/7
post-thumbnail

Hystrix?

아래와 같은 분산 환경에서 운영을 하다보면 필연적으로 분산 환경에서 서비스 중 일부에 장애가 발생할 수 있다. Hystrix는 이러한 분산 서비스 간의 상호 작용을 제어하는데 기능을 제공하는 라이브러리다.

작동 원리


1. 다른 분산된 서비스를 호출하는 HystrixCommand나 HystrixObservableCommand 객체를 생성한다
2. 커맨드를 실행할 아래의 네 가지 메소드 중 하나를 선택해 실행한다. execute(), queue() 메소드는 HystrixCommand 객체에서만 적용 가능하다

  • execute() : 동기 blocking 방식으로 HystrixCommand의 실행을 기다리며 다른 서비스로부터 단일 응답을 받는다
  • queue() : 비동기 non-blocking 방식으로 실행 결과를 다른 서비스로부터 Future 객체로 단일 응답을 받는다
    (※ Future 객체는 비동기 인터페이스로 Java 8부터 구현체 CompletableFuture가 등장했다 여기서는 비동기 인터페이스인 것만 이해했다)
  • observe() : 다른 서비스로부터 응답을 나타내는 Observable 객체를 구독하고 반환한다
  • toObservable() : 만약 Observable 객체를 구독하면 그때 응답을 반환한다
    (※ Observale 객체는 리엑티브 프로그래밍에서 사용되는 객체로, 데이터 스트림을 생성하고 이에 대한 구독을 관리한다 여기서는 모두 비동기 방식이나 queue() 메소드에서 queue를 사용했다면 observe(), toObervable()에서는 데이터 스트림을 사용하는 것으로 이해했다)
  1. 응답을 캐싱하는지 확인한다 (yes: 캐싱된 데이터를 응답)
  2. circuit breaker가 열려있는지 확인한다(yes: fallback을 응답)
  3. command 객체들의 스레드 풀, 큐, 세마포어가 full인지 확인한다(yes: fallback을 응답)
  4. HystrixCommand.run() 메소드나 HystrixObservableCommand.construct() 메소드를 실행한다
  • HystrixCommand.run() : 단일 응답을 반환하거나 예외를 던진다
  • HystrixObservableCommand.construct() : Observable 객체를 발행하거나 onError 이벤트를 보낸다
  1. 서킷 상태를 계산한다.(fallback 수를 바탕으로 서킷이 열릴건지 판단을 위해)
  2. 실패 시 fallback을 응답한다
  3. 사용자의 요청을 정상적으로 동작한 응답을 반환한다

Circuit Breaker


장애 상황이 발생하면 그 서비스와 연관된 다른 서비스들도 영향을 받게된다. 이때 circuit Breaker는 어떤 요청을 처리하는 서비스가 장애 상황에 놓이면, 해당 서비스의 상태를 일시적으로 끊어버리는 역할을 한다. 이는 장애 전파를 막기 위함이며, 서비스가 정상으로 회복되면 다시 작동을 멈춘다.

How To use

Hystrix를 사용해 응답 실패율이 50%를 초과하면 circuit breaker가 작동하도록 간단하게 구현해보도록 한다. 로그로도 작동여부를 확인할 수 있지만 netflix에서 구현한 hystrix dashboard를 통해 작동 여부를 좀 더 직관적으로 확인할 수 있다.

build.gradle

implementation group: 'org.springframework.cloud', name: 'spring-cloud-starter-netflix-hystrix', version: '2.2.10.RELEASE' // hystrix 사용을 위해 추가
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix-dashboard:2.2.10.RELEASE' // circuit breaker 작동 확인을 위해 hystrix dashboard 사용

application.yaml

hystrix:
  dashboard:
    proxy-stream-allow-list: "*" # dashboard로 모니터링할 서버 host
  command:
      circuitBreaker:
        requestVolumeThreshold: 1 # Circuit Breaker가 동작하도록 하는 요청의 최소 개수를 지정합니다.
        errorThresholdPercentage: 50 # Circuit Breaker가 열리는 실패율 임계값을 지정합니다.
        sleepWindowInMilliseconds: 5000 # Circuit Breaker가 닫힌 후 다시 열리기 전까지 대기하는 시간을 지정합니다.
      fallback:
        enabled: true
        
management:
  endpoint:
    hystrix:
      stream:
        enabled: true # dashboard로 모니터링 데이터 전송을 허용
    chaosmonkey:
      enabled: true
  endpoints:
     web:
       exposure:
         include: "*"

myprojectApplication.java

@EnableHystrix // application에 hystrix,dashboard 적용을 위해 추가
@EnableHystrixDashboard 
@SpringBootApplication
public class myprojectApplication {

    public static void main(String[] args) {
        SpringApplication.run(myprojectApplication.class, args);
        long heapSize = Runtime.getRuntime().totalMemory();
        System.out.println("HEAP Size(M) : "+ heapSize / (1024*1024) + " MB");
    }
}

studycontroller.java

@ResponseBody
    @GetMapping("/study/{id}")
    @HystrixCommand(fallbackMethod = "fallbackMethod") // fallback method 지정
    public StudyResDTO findStudy(@PathVariable("id") Long id) throws RuntimeException{
        return studyService.findStudy(id);
    }

    public StudyResDTO fallbackMethod(Long id, Throwable throwable){
        log.error(throwable.getMessage());
        return null;
    }

원래라면 hystrix를 적용한 서버와 모니터링할 서버로 따로 분리해야하지만 circuit breaker 작동 확인 여부를 구현하기위해 만든거라 한 서버에 hystrix, dashboard 모두 추가했다.
주소의 /hystrix가 dashboard 주소이고 검색창의 입력할 주소가 모니터링 대상 서버이다.

잘 적용되면 이런 창이 나온다.

Jmeter를 사용하여 1tps로 요청을 두고

level : 10, exceptionActive : true로 설정해 10번 중 1번 RuntimeException이 발생하도록 공격해봤다.


실패율이 증가했지만 아직 우리 시스템에 설정한 50%에 도달하지 못했기에 level : 2로 좀 더 공격을 해봤다.


의도대로 circuit breaker가 작동한 모습을 확인할 수 있다.

이런 카오스 엔지니어링을 통해 좀 더 견고한 서비스를 만들 수 있을 것 같다.

참고
https://github.com/Netflix/Hystrix/wiki
https://martinfowler.com/bliki/CircuitBreaker.html

profile
Just Do It!

0개의 댓글