今天來看下Hystrix的熔斷與降級。
首先什么是降級?當請求超時、資源不足等情況發生時進行服務降級處理,不調用真實服務邏輯,而是使用快速失敗(fallback)方式直接返回一個托底數據,保證服務鏈條的完整,避免服務雪崩。需要注意的是,服務降級是在客戶端層面實現的。接下來通過代碼進行一個實踐:
首先需要添加Hystrix的依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
application.yml:
server: port: 10090 spring: application: name: spring-cloud-hystrix-test eureka: client: service-url: defaultZone: http://127.0.0.1:9090/eureka fetch-registry: true register-with-eureka: true
controller層代碼實現:
@RestController public class TestController { @Autowired TestService service; @GetMapping("/hystrix/test") public String helloHystrix() { return service.test(); } }
service層代碼實現:
@Service public class TestService { @Autowired private RestTemplate restTemplate; @Autowired private DiscoveryClient discoveryClient; @HystrixCommand(fallbackMethod = "myFallback") public String test() { ServiceInstance instance = discoveryClient.getInstances("spring-cloud-service-provider").get(0); String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/test"; return restTemplate.getForObject(url, String.class); } public String myFallback() { return "fallback"; } }
這里我們指定了myFallback()作為Fallback方法,我們通過瀏覽器訪問一下這個服務試試看:
調用成功,因為現在我們的服務端並沒有出現超時等需要進行降級處理的異常。為了驗證降級我們對客戶端以及服務端的代碼進行微調。
客戶端上增加了Hystrix屬性中timeout的設置,調整為3秒鍾未取到服務端的返回,視為超時:
@HystrixCommand(fallbackMethod = "myFallback", commandProperties = { @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "3000") }) public String test() {
ServiceInstance instance = discoveryClient.getInstances("spring-cloud-service-provider").get(0); String url = "http://" + instance.getHost() + ":" + instance.getPort() + "/test"; return restTemplate.getForObject(url, String.class); }
服務端則是增加一個4秒中的sleep:
@RequestMapping(value = "/test", method = RequestMethod.GET) public String test() throws InterruptedException {
Thread.sleep(4000); return "Hello world!"; }
再次進行驗證:
這次可以看到成功觸發了降級。
再來看一下什么是熔斷。當一定時間內,異常請求比例(請求超時、網絡故障、服務異常等)達到閾值時,啟動熔斷器,熔斷器一旦啟動,則會停止調用具體服務邏輯,通過fallback快速返回托底數據,保證服務鏈的完整。看上去和降級差不多?不過熔斷是在服務端實現,目的是當服務端的某個服務出現異常后為了不影響其他客戶端的請求而做出的及時回應。
關於熔斷,我們還有必要了解一下熔斷機制的三個狀態:關閉,開啟和半開。最開始是關閉狀態,這個時候所有請求都可以通過;如果錯誤請求達到一定的閾值,就會變成開啟狀態,此時所有請求短路,直接返回失敗的響應;一段時間后,斷路器會變成半開狀態,如果下一個請求成功了,就關閉斷路器,反之就開啟斷路器。
來看一下具體的代碼實現:
@RestController public class ServiceController { @RequestMapping(value = "/test", method = RequestMethod.GET) @HystrixCommand(fallbackMethod = "myFallback", commandProperties = { @HystrixProperty(name = HystrixPropertiesManager.CIRCUIT_BREAKER_REQUEST_VOLUME_THRESHOLD, value="1"), @HystrixProperty(name=HystrixPropertiesManager.CIRCUIT_BREAKER_SLEEP_WINDOW_IN_MILLISECONDS, value="5000") }) public String test() throws Exception { System.out.println("test() called..."); throw new Exception("test exception"); } private String myFallback() { return "fallback"; } }
這里設置了熔斷的一個閾值,也就是10秒內異常請求數達到1次就進行熔斷,同時在5秒鍾后恢復請求狀態。
啟動兩個瀏覽器進行驗證:
可以看到由於服務端直接拋出異常,兩次調用均調用了托底服務,但是服務端卻只記錄了一次調用,因為第一次調用拋出異常后已經進入熔斷狀態:
同時由於設置了5秒后恢復請求,我們在5秒后再次嘗試調用,服務端又會重新記錄正常調用時的信息:
參考資料:
https://www.cnblogs.com/yb-ken/p/15068392.html
https://www.cnblogs.com/hellxz/p/8889017.html
https://www.cnblogs.com/bamboocloud/articles/10275090.html
https://www.jianshu.com/p/01efebbfc269
https://blog.csdn.net/wangchengming1/article/details/93191815
https://blog.csdn.net/tongtong_use/article/details/78611225