01. Hystrix 사용하기
Display → Product 연동 구간에 Circuit Breaker를 적용!
[display] build.gradle에 hystrix dependency추가
compile('org.springframework.cloud:spring-cloud-starter-netflix-hystrix')
[display] DisplayApplication에 @EnableCircuitBreaker추가
@EnableCircuitBreaker
[display] ProductRemoteServiceImpl에 @HystrixCommand 추가
@HystrixCommand
02. Hystrix Fallback 적용하기
가. Fallback 적용하기
git checkout tags/step-2-hystrix-fallback -b step-2-hystrix-fallback
- 개요
- Display 서비스는 외부 Server인 Product API와 연동되어있음
- Product API에 장애가 나더라도 Display의 다른 서비스는 이상없이 동작하였으면 합니다
- Product API에 응답 오류인경우, Default값을 넣어 주고 싶습니다
- [product] ProductController에서 항상 Exception 던지게 수정하기 (장애 상황 흉내)
@RestController @RequestMapping("/products") public class ProductController { @GetMapping(path = "{productId}") public String getProductInfo(@PathVariable String productId) { // return "[product id = " + productId + " at " + System.currentTimeMillis() + "]"; throw new RuntimeException("I/O Exception"); } }
- [display] ProductRemoteServiceImpl에 Fallback Method 작성하기
@Service public class ProductRemoteServiceImpl implements ProductRemoteService { private static final String url = "http://localhost:8082/products/"; private final RestTemplate restTemplate; public ProductRemoteServiceImpl(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @Override @HystrixCommand(fallbackMethod = "getProductInfoFallback") public String getProductInfo(String productId) { return this.restTemplate.getForObject(url + productId, String.class); } public String getProductInfoFallback(String productId) { return "[ this product is sold out ]"; } }
- Product → Display 호출 확인
나. Fallback 원인 출력하기
git checkout tags/step-2-hystrix-fallback2 -b step-2-hystrix-fallback2
- [display] ProductRemoteServiceImp에 Fallback Method 에 Throwable추가
@Service public class ProductRemoteServiceImpl implements ProductRemoteService { private static final String url = "http://localhost:8082/products/"; private final RestTemplate restTemplate; public ProductRemoteServiceImpl(RestTemplate restTemplate) { this.restTemplate = restTemplate; } @Override @HystrixCommand(fallbackMethod = "getProductInfoFallback") public String getProductInfo(String productId) { return this.restTemplate.getForObject(url + productId, String.class); } public String getProductInfoFallback(String productId, Throwable t) { System.out.println("t = " + t); return "[ this product is sold out ]"; } }
- Display 호출 확인
http://localhost:8081/displays/11111
2020-02-25 11:32:22.068 INFO 69092 --- [io-8081-exec-10] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet' 2020-02-25 11:32:22.068 INFO 69092 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started 2020-02-25 11:32:22.174 INFO 69092 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 106 ms t = org.springframework.web.client.HttpServerErrorException: 500 null
- 정리
- Hystrix에서 Fallback의 실행 여부는 Exception이 발생 했는가 여부
- Fallback의 정의 여부는 Circuit Breaker Open과 무관.
- Throwable 파래매터의 추가로. Fallback 원인을 알 수 있다.
03. Hystrix로 Timeout 처리하기
git checkout tags/step-2-hystrix-timeout -b step-2-hystrix-timeout
- [product] ProductController의 throw Exception을 Thread.sleep(2000)로 수정
@RestController @RequestMapping("/products") public class ProductController { @GetMapping(path = "{productId}") public String getProductInfo(@PathVariable String productId) { try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } return "[product id = " + productId + " at " + System.currentTimeMillis() + "]"; //throw new RuntimeException("I/O Exception"); } }
- [display] application.yml 수정하여 Hystrix Timeout 시간 조정하기
hystrix: command: default: # command key. use 'default' for global setting. execution: isolation: thread: timeoutInMilliseconds: 1000
- Display → Product 호출 하기
- 정리
04. Hystrix Circuit Open 테스트
git checkout tags/step-2-hystrix-circuit-open -b step-2-hystrix-circuit-open
- [display] application.yml 수정하여 Hystrix 프로퍼티 추가.
- 10초동안 20개 이상의 호출이 발생 했을때 50% 이상의 호출에서 에러가 발생하면 Circuit Open
hystrix: command: default: # command key. use 'default' for global setting. execution: isolation: thread: timeoutInMilliseconds: 3000 circuitBreaker: requestVolumeThreshold: 1 # Minimum number of request to calculate circuit breaker's health. default 20 errorThresholdPercentage: 50 # Error percentage to open circuit. default 50
- [product] ProductController 다시 수정하여 Exception 던지도록 수정
@RestController @RequestMapping("/products") public class ProductController { @GetMapping(path = "{productId}") public String getProductInfo(@PathVariable String productId) { // try { // Thread.sleep(2000); // } catch (InterruptedException e) { // e.printStackTrace(); // } // // return "[product id = " + productId + " at " + System.currentTimeMillis() + "]"; throw new RuntimeException("I/O Exception"); } }
- Display → Product 호출 확인
2020-02-25 12:38:13.284 INFO 96380 --- [io-8081-exec-10] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring FrameworkServlet 'dispatcherServlet' 2020-02-25 12:38:13.285 INFO 96380 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization started 2020-02-25 12:38:13.360 INFO 96380 --- [io-8081-exec-10] o.s.web.servlet.DispatcherServlet : FrameworkServlet 'dispatcherServlet': initialization completed in 74 ms t = org.springframework.web.client.HttpServerErrorException: 500 null t = java.lang.RuntimeException: Hystrix circuit short-circuited and is OPEN t = java.lang.RuntimeException: Hystrix circuit short-circuited and is OPEN t = java.lang.RuntimeException: Hystrix circuit short-circuited and is OPEN
- 정리