반응형

Spring Cloud Hystrix?

  • Hystrix는 분산 서비스간 통신이 원할하지 않을 경우 처리를 위해 Netflix에서 만든 라이브러리이다
  • 주문 서비스가 배송 서비스의 API를 호출했을 때 실패할 경우 주문 서비스도 올바르게 서비스할 수 없는 장애 전파 현상이 발생할 수 있다
  • 이러한 장애 전파 현상을 막기 위해서는 주문 서비스가 배송 서비스 API 호출에 실패할 경우 엑셀 파일로 남겨놨다가 배송을 할 수 있게 한다거나, 상품 추천 서비스 API 호출 실패시 디폴트로 정해진 상품을 추천해 준다던지의 처리가 필요하다.
  • 위처럼 Circuit Breaker(장애 내성)의 역할을 해주는 것이 Hystrix이다
  • Hystrix는 low-level 라이브러리이고, 최근에는 좀더 high-level로 사용하기 편한 Feign을 사용한다

Hystrix 프로젝트 설정하기

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>spring-msa-hystrix</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>spring-msa-hystrix</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>11</java.version>
        <spring-cloud.version>Hoxton.SR9</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>
@EnableHystrix 어노테이션 설정
@EnableHystrix
@SpringBootApplication
public class SpringMsaHystrixApplication {
    public static void main(String[] args) {
        SpringApplication.run(SpringMsaHystrixApplication.class, args);
    }
}
컨트롤러 작성
  • 다른 서비스의 API를 restTemplate으로 호출하는 것처럼 테스트하기 위해 편의상 동일 프로젝트 컨트롤러에 /api/other/service/ads API를 추가
  • 랜덤하게 오류를 발생시켜 어떻게 반응하는지 확인
@RequiredArgsConstructor
@RestController
public class DisplayController {
    private final DisplayService displayService;

    @GetMapping("/api/ads")
    public String getAds() {
        return displayService.getAds();
    }

    @GetMapping("/api/other/service/ads")
    public String getOtherServiceAds() {
        if (new Random().nextBoolean()) {
            throw new IllegalStateException("server error");
        }
        return "I'm Good Products";
    }
}
서비스 작성
@Service
public class DisplayService {
    private final RestTemplate restTemplate = new RestTemplate();

    @HystrixCommand(fallbackMethod = "getAdsFallback")
    public String getAds() {
        return restTemplate.getForObject("http://localhost:8080/api/other/service/ads", String.class);
    }

    private String getAdsFallback() {
        return "default ads";
    }
}
/api/ads API 호출
### 테스트
GET http://localhost:8080/api/ads
I'm Good Products
default ads

서비스 코드 상세 분석

@Service
public class DisplayService {
    private final RestTemplate restTemplate = new RestTemplate();

    @HystrixCommand(
        commandKey = "getAds",
        fallbackMethod = "getAdsFallback",
        commandProperties = {
            @HystrixProperty(name = "metrics.rollingStats.timeInMilliseconds", value = "10000"),
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000"),
            @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10"),
            @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "5"),
            @HystrixProperty(name = "circuitBreaker.sleepWindowInMilliseconds", value = "10000")
        })
    public String getAds() {
        return restTemplate.getForObject("http://localhost:8080/api/other/service/ads", String.class);
    }

    private String getAdsFallback() {
        return "기본 광고";
    }
}
  • @HystrixCommand
    • Hystrix는 @Component, @Service의 @HystrixCommand를 찾아 동작한다
  • commandKey
    • 지정해주지 않으면 디폴트로 메소드명이 들어간다
    • 실패 통계를 낼 때 해당값이 일치하는 메소드들을 함께 실패한 것으로 간주하여 통계낸다
  • fallbackMethod
    • 해당 메소드가 실패 조건에 부합된 경우 Circuit Open 상태가 되고, Circuit Open 상태일 때 대신 호출하여 다른 정상 응답을 주는 메소드를 fallbackMethod라고 한다
    • N초 동안 일어난 호출을 통계 내서 어느 정도 이상 실패했다면 몇 초 동안은 서비스 호출을 시도하지 않고 즉시 fallbackMethod를 리턴하는 상황이 Circuit Open
    • 그 이후 1회의 호출이라도 또 실패한다면 몇 초 동안 다시 Circuit Open 상태를 유지하는 것이 Circuit Half Open이라고 한다
  • metrics.rollingStats.timeInMilliseconds
    • 오류 감시 시간 (default 10s)
  • execution.isolation.thread.timeoutInMilliseconds
    • 타임아웃 3초로 지정 (default 1s)
  • circuitBreaker.errorThresholdPercentage
    • 통계를 낼 때 10% 이상 실패시 Circuit Open 상태로 전환
  • circuitBreaker.requestVolumeThreshold
    • 5회 이상 호출되면 통계 시작
  • circuitBreaker.sleepWindowInMilliseconds
    • Circuit이 한 번 열리면 10초 유지

참고

반응형

'Development > Spring' 카테고리의 다른 글

[Spring] Spring Cloud Feign  (0) 2020.12.27
[Spring] Spring Cloud Gateway  (0) 2020.12.27
[Spring] Spring Cloud Eureka  (0) 2020.12.27
[Spring] Spring Cloud Config  (0) 2020.12.27
[Spring] SQL Mapper (with MyBatis)  (0) 2020.12.27

+ Recent posts