今天來看下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