springcloud之Hystrix實現容錯處理
如果服務提供者響應非常緩慢,那麼消費者對提供者的請求就會被強制等待,知道提供者響應或超時,在高負載場景下,如果不做任何處理,那麼就會導致服務消費者的資源耗盡甚至整個系統崩潰。微服務架構的應用系統通常包含多個服務層,微服務之間通過網路進行通訊,從而支撐起整個應用系統,服務之間難免存在依賴關係,事實上,微服務並非總是能夠保持可用狀態,而網路也往往非常脆弱,因此難免有些請求會失敗。
我們把“基礎服務故障”而導致“級聯故障”的現象稱為雪崩效應。雪崩效應描述的是提供者不可用導致消費者不可用,並將不可用逐漸傳遞放大的過程。
要想防止雪崩效應,必須有一個強大的容錯機制,它應該實現以下兩點:
- 為網路請求設定超時:通常情況下,一次遠端呼叫對應著一個執行緒/程序,如果響應太慢,這個執行緒/程序就得不到釋放,進而導致系統資源耗盡,最終導致服務不可用 。
- 使用斷路器模式:就比如家裡如果沒有斷路器,當電流過載時(功率過大、短路等),電路沒有斷開,電路就會迅速發熱,燒斷電路甚至引起火災,使用斷路器之後,一旦電流過載就會跳閘切斷電路,從而保護電路安全。同理,如果某個微服務的請求大量超時了,再去產生新的請求已經沒有任何意義,只會白白消耗資源。微服務裡斷路器可以理解為對容易導致錯誤的操作的一個代理。這種代理能夠統計一段時間內呼叫失敗的次數,並決定是正常請求依賴的服務還是直接返回。斷路器可以快速失敗,如果它在一段時間內檢測到許多類似的錯誤,就會在之後的一段時間內,強迫對該服務的呼叫失敗,不再請求所依賴的服務,這樣就減少了cpu的超時等待時間。斷路器也可以自動診斷依賴的服務是否已經恢復正常,這樣,微服務就有了“自我修復”的功能:當依賴的服務不正常時開啟快速失敗機制,防止雪崩效應;當發現服務恢復正常時,又會恢復請求。
Hystrix就是spring cloud中一個斷路器,它是由Netflix開源的一個延遲和容錯庫,用於隔離遠端系統,服務或者第三方庫,防止級聯失敗,從而提升系統的可用性與容錯性。Hystrix主要通過以下幾點實現延遲和容錯:
- 包裹請求:使用HystrixCommand包裹對依賴的呼叫邏輯,每個命令在獨立執行緒中執行(這裡用了“命令模式”)
- 跳閘機制:當某個服務的錯誤率超過一定閾值時,Hystrix可以自動或者手動跳閘,停止該服務的請求一段時間
- 資源隔離:Hystrix為每個依賴都維護了一個小型的執行緒池(或者訊號量)。如果該執行緒池已滿,發往該依賴的請求就會被立即拒絕,而不是排隊等候,加速失敗判定
- 監控:Hystrix可以近乎實時的監控執行指標和配置的變化,例如成功或失敗等
- 回退機制:當請求失敗、超時、被拒絕,或當斷路器開啟時,執行回退邏輯。這個可以由開發人員自行提供
- 自我修復:斷路器開啟一段時間後,會自動進入“半開”狀態(探測服務是否可用,如還是不可用,再次退回開啟狀態)。
在Ribbon中使用Hystrix:
新增maven依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
在程式的啟動類ServiceRibbonApplication 加@EnableHystrix註解開啟Hystrix:
@SpringBootApplication @EnableEurekaClient @EnableDiscoveryClient @EnableHystrix public class ServiceRibbonApplication { public static void main(String[] args) { SpringApplication.run( ServiceRibbonApplication.class, args ); } @Bean @LoadBalanced RestTemplate restTemplate() { return new RestTemplate(); } }
在service方法中新增@HystrixCommand註解,開啟熔斷功能,並指定回退方法fallbackMethod ,進行快速失敗操作:
@Service public class HelloService { @Autowired RestTemplate restTemplate; @HystrixCommand(fallbackMethod = "hiError") public String hiService(String name) { return restTemplate.getForObject("http://SERVICE-HI/hi?name="+name,String.class); } public String hiError(String name) { return "hi,"+name+",sorry,error!"; } }
在Feign中使用熔斷器
在配置檔案中開啟:feign.hystrix.enabled=true
在FeignClient註解的介面方法上,增加了fallback指定類:
@FeignClient(value = "service-hi",fallback = SchedualServiceHiHystric.class) public interface SchedualServiceHi { @RequestMapping(value = "/hi",method = RequestMethod.GET) String sayHiFromClientOne(@RequestParam(value = "name") String name); }
然後實現該類和方法即可。這裡的fallback方法執行並不代表斷路器已經開啟,請求失敗、超時、被拒絕等情況下都會執行回退邏輯。
Hystrix執行緒隔離與傳播上下文:
執行緒隔離的策略分兩種:分別是執行緒隔離和訊號量隔離。執行緒隔離表示HystrixCommand將會在單獨的執行緒上執行,併發請求受執行緒池中執行緒數量的限制;訊號量隔離是指HystrixCommand將會在呼叫執行緒上執行,開銷相對較小,併發請求受訊號量個數限制。Hystrix預設並推薦使用執行緒隔離模式,因為這種方式有除了網路超時以外的額外保護層,只有在呼叫負載非常高時才需要使用訊號量,可以減少執行緒開銷。