前言?
-
Netflix Hystrix斷路器是什么?
Netflix Hystrix是SOA/微服務架構中提供服務隔離、熔斷、降級機制的工具/框架。Netflix Hystrix是斷路器的一種實現,用於高微服務架構的可用性,是防止服務出現雪崩的利器。
-
為什么需要斷路器
在分布式架構中,一個應用依賴多個服務是非常常見的,如果其中一個依賴由於延遲過高發生阻塞,調用該依賴服務的線程就會阻塞,如果相關業務的QPS較高,就可能產生大量阻塞,從而導致該應用/服務由於服務器資源被耗盡而拖垮。
另外,故障也會在應用之間傳遞,如果故障服務的上游依賴較多,可能會引起服務的雪崩效應。就跟數據癱瘓,會引起依賴該數據庫的應用癱瘓是一樣的道理。
當一個應用依賴多個外部服務,一切都正常的情況下,如下圖:

如果其中一個依賴發生延遲,當前請求就會被阻塞

出現這種情況后,如果沒有應對措施,后續的請求也會被持續阻塞

每個請求都占用了系統的CPU、內存、網絡等資源,如果該應用的QPS較高,那么該應用所以的服務資源會被快速消耗完畢,直至應用死掉。如果這個出問題的依賴(Dependency I),不止這一個應用,亦或是受影響的應用上層也有更多的依賴,那就會帶來我們前面所提到的服務雪崩效應。 所以,為了應對以上問題,就需要有支持服務隔離、熔斷等操作的工具。
Hystrix 簡介
-
Hystrix具備哪些能力/優點?
在通過網絡依賴服務出現高延遲或者失敗時,為系統提供保護和控制 可以進行快速失敗,縮短延遲等待時間和快速恢復:當異常的依賴回復正常后,失敗的請求所占用的線程會被快速清理,不需要額外等待 提供失敗回退(Fallback)和相對優雅的服務降級機制 提供有效的服務容錯監控、報警和運維控制手段
-
Hystrix 如何解決級聯故障/防止服務雪崩?
-
Hystrix將請求的邏輯進行封裝,相關邏輯會在獨立的線程中執行
-
Hystrix有自動超時策略,如果外部請求超過閾值,Hystrix會以超時來處理
-
Hystrix會為每個依賴維護一個線程池,當線程滿載,不會進行線程排隊,會直接終止操作
-
Hystrix有熔斷機制: 在依賴服務失效比例超過閾值時,手動或者自動地切斷服務一段時間 所以,當引入了Hystrix之后,當出現某個依賴高延遲的時候
Hystrix 工作原理
-
Hystrix工作流

-
創建HystrixCommand 或者 HystrixObservableCommand 對象 -
執行命令execute()、queue()、observe()、toObservable() -
如果請求結果緩存這個特性被啟用,並且緩存命中,則緩存的回應會立即通過一個Observable對象的形式返回 -
檢查熔斷器狀態,確定請求線路是否是開路,如果請求線路是開路,Hystrix將不會執行這個命令,而是直接執行getFallback -
如果和當前需要執行的命令相關聯的線程池和請求隊列,Hystrix將不會執行這個命令,而是直接執行getFallback -
執行HystrixCommand.run()或HystrixObservableCommand.construct(),如果這兩個方法執行超時或者執行失敗,則執行getFallback() -
Hystrix 會將請求成功,失敗,被拒絕或超時信息報告給熔斷器,熔斷器維護一些用於統計數據用的計數器。這些計數器產生的統計數據使得熔斷器在特定的時刻,能短路某個依賴服務的后續請求,直到恢復期結束,若恢復期結束根據統計數據熔斷器判定線路仍然未恢復健康,熔斷器會再次關閉線路。 -
依賴隔離Hystrix采用艙壁隔離模式隔離相互之間的依賴關系,並限制對其中任何一個的並發訪問。
可能會有人有疑問,為什么不依賴於HTTP Client去做容錯保護(快速失敗、熔斷等),而是在訪問依賴之外通過線程&線程池隔離的方式做這個斷路器(Hystrix)`
主要是以下幾個方面:
-
不同的依賴執行的頻率不同,需要分開來對待 -
不同的依賴可能需要不同的Client的工具/協議來訪問,比如我們可能用HTTP Client,可能用Thrift Client。 -
Client在執行的過程中也可能會出現非網絡異常,這些都應該被隔離 -
Client的變化會引起斷路器的變化
SpringCloud:Ribbon + Hystrix應用
-
項目中引入Hystrix
修改pom.xml,引入Spring Cloud Netflix Hystrix
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
-
配置Hystrix啟動類
修改啟動類Application.java,增加@EnableHystrix注解開啟Hystrix
@EnableHystrix
@EnableDiscoveryClient
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
}
-
斷路處理實現
修改TestService.java,增加斷路器功能
-
在index方法上增加注解 @HystrixCommand並通過fallbackMethod參數指定斷路后執行的方法 -
定義斷路處理方法,返回服務/操作斷路后的提示
@Service
public class TestService {
@Autowired
private RestTemplate restTemplate;
@HystrixCommand(fallbackMethod = "indexError")
public Object index() {
return restTemplate.getForObject("http://testservice", String.class);
}
public Object plus(int numA, int numB) {
String url = String.format("http://testservice/plus?numA=%s&numB=%s", numA, numB);
return restTemplate.getForObject(url, String.class);
}
public Object indexError() {
return "{\"code\": 999,\"message\": \"服務斷路\"}";
}
}
-
斷路處理測試
啟動 Application 項目, 訪問:http://localhost:8604/ti ,將看到
{
"code": 0,
"message": "hello",
"content": null,
"serviceName": "testservice",
"host": "localhost:8602"
}
關閉testservice,然后再訪問 http://localhost:8604/ti ,將看到
{
"code": 999,
"message": "服務斷路"
}
至此完成Ribbon+Hystrix的熔斷。
SpringCloud:Feign + Hystrix應用
-
開啟Hystrix 修改application.yml,開啟Hystrix
feign:
hystrix:
enabled: true
-
斷路處理實現
新建 TestServiceHystrix.java作為TestService的斷路處理實現
@Component
public class TestServiceHystrix implements TestService {
@Override
public String indexService() {
return "{\"code\": 999,\"message\": \"服務斷路\"}";
}
@Override
public Result plusService(int numA, int numB) {
Result result = new Result();
result.setCode(999);
result.setMessage("服務斷路");
return new Result();
}
@Override
public Result plusabService(Plus plus) {
Result result = new Result();
result.setCode(999);
result.setMessage("服務斷路");
return new Result();
}
@Override
public Result plus2Service(Plus plus) {
Result result = new Result();
result.setCode(999);
result.setMessage("服務斷路");
return new Result();
}
}
-
修改TestService,指定fallback類
@FeignClient(value = "testservice", fallback = TestServiceHystrix.class)
public interface TestService {
@RequestMapping(value = "/", method = RequestMethod.GET)
String indexService();
@RequestMapping(value = "/plus", method = RequestMethod.GET)
Result plusService(@RequestParam(name = "numA") int numA, @RequestParam(name = "numB") int numB);
@RequestMapping(value = "/plus", method = RequestMethod.POST, consumes = "application/json")
Result plusabService(Plus plus);
@RequestMapping(value = "/plus2", method = RequestMethod.POST)
Result plus2Service(@RequestBody Plus plus);
}
-
啟動 feign Application 項目
-
訪問:http://localhost:8605/ti ,將看到
{
"code": 0,
"message": "hello",
"content": null,
"serviceName": "testservice",
"host": "localhost:8602"
}
-
關閉testservice,然后再訪問 http://localhost:8605/ti ,將看到
{
"code": 999,
"message": "服務斷路"
}
至此完成Feign+Hystrix的熔斷。
結束
歡迎關注公眾號! 公眾號回復:
入群
,掃碼加入我們交流群!