一文帶大家徹底搞懂Hystrix

作者:陸陸起飛啦

Netflix Hystrix斷路器是什麼?

Netflix Hystrix是SOA/微服務架構中提供服務隔離、熔斷、降級機制的工具/框架。Netflix Hystrix是斷路器的一種實現,用於高微服務架構的可用性,是防止服務出現雪崩的利器。

為什麼需要斷路器

在分散式架構中,一個應用依賴多個服務是非常常見的,如果其中一個依賴由於延遲過高發生阻塞,呼叫該依賴服務的執行緒就會阻塞,如果相關業務的QPS較高,就可能產生大量阻塞,從而導致該應用/服務由於伺服器資源被耗盡而拖垮。

另外,故障也會在應用之間傳遞,如果故障服務的上游依賴較多,可能會引起服務的雪崩效應。就跟資料癱瘓,會引起依賴該資料庫的應用癱瘓是一樣的道理。

當一個應用依賴多個外部服務,一切都正常的情況下,如下圖:

一文帶大家徹底搞懂Hystrix

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

一文帶大家徹底搞懂Hystrix

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

一文帶大家徹底搞懂Hystrix

每個請求都佔用了系統的CPU、記憶體、網路等資源,如果該應用的QPS較高,那麼該應用所以的服務資源會被快速消耗完畢,直至應用死掉。如果這個出問題的依賴(Dependency I),不止這一個應用,亦或是受影響的應用上層也有更多的依賴,那就會帶來我們前面所提到的服務雪崩效應。 所以,為了應對以上問題,就需要有支援服務隔離、熔斷等操作的工具。

Hystrix 簡介

Hystrix具備哪些能力/優點?

在透過網路依賴服務出現高延遲或者失敗時,為系統提供保護和控制 可以進行快速失敗,縮短延遲等待時間和快速恢復:當異常的依賴回覆正常後,失敗的請求所佔用的執行緒會被快速清理,不需要額外等待 提供失敗回退(Fallback)和相對優雅的服務降級機制 提供有效的服務容錯監控、報警和運維控制手段

Hystrix 如何解決級聯故障/防止服務雪崩?

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

org。springframework。cloud spring-cloud-starter-netflix-hystrix

配置Hystrix啟動類

修改啟動類Application。java,增加@EnableHystrix註解開啟Hystrix

@EnableHystrix@EnableDiscoveryClient@SpringBootApplicationpublic 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引數指定斷路後執行的方法

定義斷路處理方法,返回服務/操作斷路後的提示

@Servicepublic 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的斷路處理實現

@Componentpublic 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的熔斷。

作者:陸陸起飛啦