MS 와 같은 분산환경에서는 에러가 발생하거나 실패할 시점이 다양하다.
MSA 에서는 빠른 실패와 장애 적응, 회복력을 중점으로 바라보며 실패를 수용하는 태도를 보인다.
- 치명적인 부분은 장애 전파 시의 경우이며, 이는 대부분 의존성 발생 지점에서 나타나는 일이다.
- Hystrix 가 하는 일은 회로 차단기와 같다.
- 의존성이 발생하는 포인트를 분리하고, 장애 발생시 끊음으로서 장애 전파가 일어나지 않게한다.
- FallBack 기능으로 미리 정의된 값을 Return 시킨다.
특정 서비스나 REST API 호출 결과가 비정상일 경우, 장애 전이 방지를 위해 Zuul 같은 Gateway API , 각 서비스에 있는 Hystrix 에서 호출을 자동으로 차단합니다.
기능
- 장애 전파 방지
- 빠른 실패와 빠른 복구
- 실시간 모니터링, 알람, 설정변경
장애 전파와 빠른 실패 / 빠른복구
- MSA 환경에서 서비스가 작동 중지되면 의존 서비스에 장애가 전파될 수 있음.
- 분산 환경으로 인해 Log Trace 를 하기가 어려움
- 장애 전파를 막기 위해 Hystrix 는 Circuit Breaker Pattern 을 따름
- Closed : 초기 상태. 정상 실행
- Open : 에러율이 임계치를 넘음, 모든 Connection 차단. 해당 서비스 호출 시 FallBack 실행
- Half-Open : Open 상태 이후 시간 경과 시 Half-Open 상태, 주기적으로 접속 시도 후 성공시 Closed, 실패시 Open
Hystrix Monitoring
- Hystrix 적용 App 은 /hystrix.stream EndPoint 를 가진다.
- 각 App API 상태 및 Circuit 정보를 Hystrix DashBoard 에서 모니터링 가능하다.
- Hystrix Turbin 사용시 여러 App 의 Hystrix 데이터를 집계하여 하나의 대시보드에서 볼 수 있다.
적용방법
- Eureka Service , Eureka Compoent 에 적용 가능.
- 필요 의존 : org.springframework.cloud:spring-cloud-starter-nexflix-hystrix
- Spring Boot 2.4.0 이하로 사용해야함
plugins {
id 'org.springframework.boot' version '2.3.6.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "Hoxton.SR9")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-zuul'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
test {
useJUnitPlatform()
}
- @Configuration 클래스에 @EnableCircuitBreaker 선언
@SpringBootApplication(scanBasePackages = "com.example")
@EnableCircuitBreaker
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
- 메서드 레벨에 @HystrixCommand 선언 , fallbackMethod 속성에 메서드 이름 기입
- fallBack 메서드 는 기존 메서드와 파라미터, 리턴 값이 반드시 동일
@GetMapping("/test/{id}")
@HystrixCommand(fallbackMethod = "fallback")
public ResponseEntity<Object> test(@PathVariable("id") Long id) throws Exception {
ResponseEntity<Object> responseEntity = null;
try{
Account account = testService.getAccount(id);
responseEntity = ResponseEntity.status(HttpStatus.OK).body(account);
}catch(Exception e){
System.out.println(e.getMessage());
throw new RuntimeException();
}
return responseEntity;
}
// fallback 메서드는 접근제어자를 제외한 리턴, 파라미터 일치시켜야함
private ResponseEntity<Object> fallback(@PathVariable("id") Long id){
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new String("Hello Fallback Your Input is : "+id));
}
application.yml
#Feign Client
feign:
hystrix:
enabled: true #feignClient 에서Hystrix 사용 허용
client:
config:
default: #feignClient 설정 시작
connection-timeout: 5000 #커넥션 요청 타임아웃
read-timeout: 5000 #응답 타임아웃
logger-level: basic # 로거 레벨설정
# feign client log 레벨
# NONE : 남기지 않음, default
# BASIC : Request Method, URL , ResponseCode, 실행시간
# HEADERS : BASIC + Request/ Response Header 정보
# FULL : HEADERS + bodym metadata 정보
#Circuit Breaker
#Hystrix 는 Thread Pool 에서 관리 된다.
hystrix:
threadpool:
default:
maximum-size: 10 # Thread Poll 크기 default 10
command:
defualt:
execution:
isolation:
thread:
timeout-in-milliseconds: 1000 # 1초 지연시 fallback, default 1000
metrics:
rooling-status:
time-in-milliseconds: 100000 # 오류 감시 시간 default 10000
circuit-breaker:
request-volume-threshold: 5 # 감시 시간내의 요청 수 default 20
error-threshold-percentage: 50 # 감시 시간내의 요청 수가 해당 % 를 넘으면 OPEN default 50
#Actuator
management:
endpoints:
web:
exposure:
include: ["health", "info", "hystrix.stream"]
Feign 환경에서의 Hystrix 사용
- 의존 ,어노테이션 동일 @HystrixCommand 대신 @FeignClient 의 fallback 속성에 구현클래스 정의.
- 구현클래스에서 재정의한 메서드가 FallBack 메서드가 됨
- @FeignClient 의 fallbackFactory 속성에 FallbackFactory<FeignService> 상속 클래스 지정
- FallbackFactory<FeignService> 상속 클래스 작성 후 익명 구현 클래스 리턴함으로서 FallBack 등록
@SpringBootApplication
@EnableFeignClients
@EnableDiscoveryClient
@EnableCircuitBreaker
public class EurekaClientApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaClientApplication.class, args);
}
}
//
@FeignClient(name = "WEB",fallback = CustomFallback.class)
public interface WebClient {
@GetMapping("/test/{id}")
public ResponseEntity<Object> WebClientApiTest(@PathVariable("id") Long id);
}
//
@Component
public class CustomFallback implements WebClient {
@Override
public ResponseEntity<Object> WebClientApiTest(Long id) {
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Fall Back Method Execution Your Param : "+id);
}
}
FallBackFactory 사용 방법
@FeignClient(name = "auth-service", path = "/api/auth", fallbackFactory = AuthClientFallbackFactory.class)
public interface AuthClient {
@PostMapping("/ip/check")
Map getIpCheck(@RequestBody Map map);
@PostMapping("/ip/swaggerAccess")
List<String> swaggerAccess(@RequestBody Map map);
}
//
@Slf4j
@Component
class AuthClientFallbackFactory implements FallbackFactory<AuthClient> {
@Override
public AuthClient create(Throwable cause) {
return new AuthClient() {
@Override
public Map getIpCheck(Map map) {
log.error(cause.getMessage());
return new HashMap();
}
@Override
public List<String> swaggerAccess(Map map) {
log.error(cause.getMessage());
return new ArrayList<String>();
}
};
}
}
Hystrix Monitoring => Hystrix DashBoard
Hystrix 를 사용하는 Service
- Hystrix 를 사용 중인 Service 는 endpoint를 열기위해 spring-boot-starter-actuator 의존 필요.
- Hystrix 를 사용하는 Service 에서 /actuator 로 접근하면 /actuator/hystrix.stream url 존재.
- doli0413.tistory.com/601?category=934911
implementation 'org.springframework.boot:spring-boot-starter-actuator'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix'
# application.yml
#Actuator
management:
endpoints:
web:
exposure:
include: ["health", "info", "hystrix.stream"]
Hystrix-DashBoard Server
- org.springframework.cloud:spring-cloud-starter-netfilx-hystrix-dashboard 의존 필요
- @Configuration 클래스 > @SpringBootApplication 기술 클래스에 @EnableHystrixDashboard 선언
- 로컬 -> http://localhost:port/hystrix 접근
- Hystrix 사용 Service 의 /actuator/hystrix.stream 으로 모니터링 시작.
plugins {
id 'org.springframework.boot' version '2.3.6.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "Hoxton.SR9")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-hystrix-dashboard'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
test {
useJUnitPlatform()
}
@SpringBootApplication
@EnableHystrixDashboard
public class HystrixDashboardApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixDashboardApplication.class, args);
}
}
Hystrix-Turbine
- Hystrix 의존성을 가지고 있는 서비스 + Eureka 에 등록된 서비스에 한하여 통합 모니터링 기능을 제공
- actuator 로 http://localhost:port/actuator/hystrix.stream 으로 각 서버의 상태를 점검하고 있으니 해당 End Point 를 허용해야 하는 듯 하다.
- 필요 의존 : org.springframework.cloud:spring-cloud-starter-netflix-hystrix-turbine
- 유레카 서버에 등록시키기 위해 o.s.c:spring-cloud-starter-netfilx-eureka-client 도 필요하다.
- @Configuration 기술 클래스에 @EnableTurbine 을 선언
- application.yml 에 모니터링 할 Eureka Service 이름을 기술한다.
- Hystrix DashBoard 에 들어가서 http://localhost:port/turbine.stream 으로 접근하면 모니터링 화면 접근 가능하다.
plugins {
id 'org.springframework.boot' version '2.3.6.RELEASE'
id 'io.spring.dependency-management' version '1.0.10.RELEASE'
id 'java'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
ext {
set('springCloudVersion', "Hoxton.SR9")
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client'
implementation 'org.springframework.cloud:spring-cloud-starter-netflix-turbine'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
dependencyManagement {
imports {
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
}
}
test {
useJUnitPlatform()
}
main
@SpringBootApplication
@EnableTurbine
@EnableDiscoveryClient
public class HystrixTurbineApplication {
public static void main(String[] args) {
SpringApplication.run(HystrixTurbineApplication.class, args);
}
}
application.yml
server:
port: 8888
spring:
application:
name: hystrix-turbine
eureka:
client:
service-url:
defaultZone: ${EUREKA_SERVER_LIST:http://localhost:8761/eureka/}
registry-fetch-interval-seconds: 1
turbine:
cluster-name-expression: new String("default")
app-config: ACCOUNT-CONSUME-API,CLIENT-ONE # 서비스 목록
'Cloud' 카테고리의 다른 글
Config Server (0) | 2020.12.14 |
---|---|
Sleuth & ZipKin (0) | 2020.12.14 |
Feign (0) | 2020.12.08 |
Ribbon (0) | 2020.12.08 |
Zuul (0) | 2020.12.07 |