반응형
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 |