코알못

5분 안에 구축하는 hystrix 본문

JAVA

5분 안에 구축하는 hystrix

코린이s 2022. 1. 30. 23:52
728x90

hystrix 를 사용하고자 하는 이유는 아래와 같다!

  • A 기능에 오류가 났을시 A가 복구 될 동안 더이상 호출하지 않음으로써 부하를 주고 싶지 않다. (Circuit Open)
  • A 기능에 오류가 났을시 B 기능으로 대체하고 싶다. (Fallback)
  • B기능 실행 중에 A 기능이 복구가 된다면 다시 A 기능을 실행 시키고 싶다.(Circuit Close)

물론 try, catch 를 이용하여 해당 기능을 만들수 있으나, 직관적으로 볼 수 있어 코드가 깔끔하고 유지보수가 어렵지 않게 된다.

자 그럼 만들어 보자 !

# build.gradle

- 아래 사이트에서 원하는 버전, 빌드 도구 선택하여 정의

- meven :  https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-netflix-hystrix/2.2.9.RELEASE

dependencies {
..
    implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix:2.2.9.RELEASE' // hystrix
}

 

# Service

import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty;
import org.springframework.stereotype.Service;

@Service
public class HystrixService {

    /***
     * commandKey 는 안쓰면 자동으로 메소드 명으로 지정됨
     * 다른 패키지에 같은 매소드 명이 있다면 잘못 동작할 가능성이 있으니 지정 하는 것이 좋다.
     * execution.isolation.thread.timeoutInMilliseconds : 해당 시간 동안 메서드가 끝나지 않으면 circuit open
     * metrics.rollingStats.timeInMilliseconds : circuit open 조건 : 해당 시간 동안
     * circuitBreaker.errorThresholdPercentage : circuit open 조건 : 해당 에러 퍼센트만큼 실패시 오픈
     * circuitBreaker.requestVolumeThreshold : circuit open 조건 : 최소 판단 하기 위해 해당 요청 건수만큼 들어와야 한다.
     * circuitBreaker.sleepWindowInMilliseconds : circuit open 시 지속 될 시간
     * ms 단
     * @return
     */
    @HystrixCommand(commandKey = "A", fallbackMethod = "B", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "20"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "10"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000")
            // 10 초 동안 10번 호출 중 20% 실패시(2번 실패시) 10초간 fallback 메소드 호출
            // 단, 해당 메소드가 3초 안에 끝나지 않을시 fallback 메소드 호출
    })
    public String A(){
        return "A";
    }

    public String B(){
        return "B";
    }

# controller

import com.code.service.HystrixService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @Autowired
    public HystrixService hystrixService;

    @RequestMapping(value = "/")
    public String test(){
        return hystrixService.A();
    }

}

# application

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.hystrix.EnableHystrix;

@EnableHystrix
@SpringBootApplication
public class HystrixApplication {

    public static void main(String[] args) {
        SpringApplication.run(HystrixApplication.class, args);
    }

}

 

셋팅을 완료 하였으면 테스트를 진행한다!

1. 정상 서비스 경우

- 서킷 브레이크가 클로즈된 상태로 A를 리턴한다.

2. 응답 시간이 3s 이상 소요시

# service

    public String A(){
        try{
            Thread.sleep(4000);
        }catch (Exception e){
            log.error("### Exception");
        }
        return "A";
    }

- 4초 뒤에 B를 응답한다.

3. 10초 안에 10번 호출하여 20% 2번 실패시 (10번 중에 2번만 errYn 을 true로 보내어 에러를 발생 시킨다.)

# controller

  @RequestMapping(value = "/")
    public String test(@RequestParam Boolean errYn) throws Exception{
        return hystrixService.A(errYn);
    }

# service

// 에러로 인식하기 위해서는 try catch 를 제거 해야함
 public String A(Boolean errYn) throws Exception{
        if(errYn){
            throw new Exception();
        }
        return "A";
    }

- 2번 실패에 대한 응답값은 'B' 나머지 8번은 'A' 로 나가다가 10초뒤에 에러를 발생시키지 않아도 통계상 에러 기준에 해당 되어 더이상 'A' 를 호출하지 않고 'B'를 응답한다. 그리고 10초 뒤에 A 메소드를 호출하여 응답이 정상이니 'A' 를 리턴한다.

 

<참고 사항>

1. [에러] Post-processing of merged bean definition failed

- 원인 : spring boot 와 spring cloud(hystrix) 버전이 호환되지 않아 발생하는 이슈

- 해결 : spring boot 버전을 낮추어(다른 문서에 2.3.X 면 된다고 함) 해결 (2.5.6 > 2.3.8.RELEASE)

2. [설정] 메소드 내에 응답 시간이 5s 이상 걸리고, timeout 시간이 3s 로 되어 있어도 이전 연결을 끊지 않고 5s 뒤에 연결이 끊어지므로 (= 5초 뒤에 fallback 메소드 호출하여 응답) http client time out 설정을 하는것이 좋다.

3. [설정] hystrix 설정을 메소드 단위가 아니라 전체적으로 적용하고 싶다면 application.yml에 정의 하면 된다.

# application.yml

hystrix:
  command:
    default:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

아래와 같이 application.yml 에서 commendKey 별로 적용도 가능하다.

hystrix:
  command:
    A:
      execution:
        isolation:
          thread:
            timeoutInMilliseconds: 3000

:: https://github.com/works-code/hystrix

 

GitHub - works-code/hystrix: hystrix 간단 프로젝트 (with spring boot)

hystrix 간단 프로젝트 (with spring boot). Contribute to works-code/hystrix development by creating an account on GitHub.

github.com

 

728x90
Comments