Spring Boot Hystrix 시작하기
Spring Boot Hystrix 시작하기
Hystrix
Netflix가 만든 fault tolerance library
장애 전파 방지 & resilience
Annotation, 상속으로 사용 가능 - 개인 개발자가 쉽게 결정할 수 있음
기능적 관점에서 본 4가지 기능 circuit breaker fallback thread isolation timeout
Hystrix command를 호출할 때 벌어지는 일 API caller/callee가 다른 스레드에서 수행됨 (thread isolation) Exception 발생 여부를 기록하고 통계를 낸다. 통계에 따라 circuit open 여부를 결정한다. (circuit breaker) 실패한 경우 (exception) 사용자가 제공한 메소드를 대신 실행한다. (fallback) 특정 시간동안 메소드가 종료되지 않은 경우 exception을 발생시킨다. (timeout)
실습
2개의 프로젝트를 생성해 하나는 API caller, 하나는 callee의 역할을 수행하도록 구현
caller project - sushi, callee project - salad
1. 두 Spring boot WEB 프로젝트 생성
2. application.properties에 server.port를 각각 지정해서 포트가 안겹치게 함
salad - application.properties
server.port = 8081
sushi - application.properties
server.port = 8082
3. pom.xml - dependency 설정
org.springframework.cloud 하위 dependency 적용을 위한 dependencyManagement 설정
org.springframework.cloud spring-cloud-dependencies Finchley.RELEASE pom import
webflux, hystrix, hystrix-dashboard dependency 추가
org.springframework.boot spring-boot-starter-webflux org.springframework.cloud spring-cloud-starter-netflix-hystrix org.springframework.cloud spring-cloud-starter-netflix-hystrix-dashboard
4. 소스 작성
(Callee) salad project - SaladConroller
package com.example.salad; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class SaladController { @GetMapping("/salad") public String getSalad() throws InterruptedException { return "맛있는 샐러드"; } }
(Caller) sushi project - SushiApplication
package com.example.sushi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.cloud.netflix.hystrix.EnableHystrix; @EnableHystrix @SpringBootApplication public class SushiApplication { public static void main(String[] args) { SpringApplication.run(SushiApplication.class, args); } }
(Caller) sushi project - SushiConroller
package com.example.sushi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class SushiController { @Autowired private SushiService sushiService; @GetMapping("/salad") public String getSalad() { return sushiService.getSalad(); } }
(Caller) sushi project - SushiService
package com.example.sushi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; import org.springframework.web.reactive.function.client.WebClient; import com.netflix.hystrix.contrib.javanica.annotation.HystrixProperty; import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand; /* * Hystrix는 기본적으로 @Component / @Service를 찾고 * 그 안에 있는 @HystrixCommand를 찾아 동작한다. */ @Service public class SushiService { @Autowired private WebClient.Builder webClientBuilder; @HystrixCommand(commandKey = "sushi", fallbackMethod = "getSaladFallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "1000"), // set timeout value 1 sec @HystrixProperty(name = "circuitBreaker.errorThresholdPercentage", value = "10"), // error 비율이 10% 이상 발생하면 Circuit open @HystrixProperty(name = "circuitBreaker.requestVolumeThreshold", value = "2") // 2회 이상 호출되면 통계 시작 }) public String getSalad() { WebClient webClient = webClientBuilder.baseUrl("http://localhost:8081").build(); //baseURL이 localhost:8081인 webClientBuilder를 가져온다. return webClient.get() // get 방식으로 가져온다. .uri("/salad") // baseURL 이후의 URI /salad 이다. .retrieve() // 클라이언트 메세지를 보낸다. .bodyToMono(String.class) // body type은 string이다. .block(); // 가져온 뒤 리턴한다. } public String getSaladFallback() { return "Hello SaladFallback!"; } }
5. 빌드
정상적으로 Callee project의 메소드가 호출되는 것 확인
6. 에러 발생
(Callee) salad project - SaladConroller에서 오류가 나도록 수정
package com.example.salad; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class SaladController { @GetMapping("/salad") public String getSalad() throws InterruptedException { throw new RuntimeException("My I/O Exception"); } }
직접 callee project의 API를 호출하면 에러가 나는 것 확인할 수 있다.
Caller project의 메소드 호출 시 아래처럼 fallback method가 실행되는 것을 확인할 수 있다.
참고
https://www.youtube.com/watch?v=J-VP0WFEQsY&feature;=youtu.be [11번가 Spring Cloud 기반 MSA로의 전환 - 지난 1년간의 이야기]
https://jeong-pro.tistory.com/183 [기본기를 쌓는 정아마추어 코딩블로그]
from http://strawberry-toast.tistory.com/52 by ccl(A) rewrite - 2020-03-06 23:55:30
댓글
댓글 쓰기