在一個分佈式系統裏,一個服務每每要調用多個服務,可能存在某個服務調用失敗, 好比超時、異常等,前端
要使用容錯框架保證在某些服務調用出問題時,不會拖垮整個調用鏈路,系統依然可用。git
Hystrix是一個容錯框架,提供了隔離、熔斷、服務降級、監控、cache等功能,能夠有效防止被調服務故障形成的級聯故障。github
和eureka、ribbon、feign同樣,hystrix也是Netflix旗下的項目,都被SpringCloud集成了。redis
當此消費者對某提供者請求個數較多時,消費者能夠限制自身對提供者發起的請求個數,請求個數超過指定的值時,使請求快速失敗。spring
Hystrix的限流方式有2種:線程池、信號量。api
監控請求的失敗率(必定時間內,請求失敗個數)達到閾值,就打開斷路器,熔斷鏈路,使後續的請求快速失敗。tomcat
熔斷服務,包含被調用者、鏈路的下游服務,防止下游服務的故障影響到上游服務。springboot
服務調用失敗默認會返回一堆英文的錯誤信息給用戶,很不友好。網絡
服務降級是在服務調用失敗時自動執行預案,預案使用相同參數表、返回值類型,是備胎、次選,併發
預案能夠只保留核心業務、拋棄不重要的業務,好比電商網站qps很大時,用戶查詢商品信息這一操做,標準業務是獲取商品信息+評論+類似商品(商品推薦),預案只保留查詢商品信息這一核心業務,去掉獲取評論、推薦商品等非核心業務。
預案也能夠連核心業務都不要,直接給出「太擠了,請稍後重試」之類的友好提示。
相同點:從可用性和可靠性觸發,防止系統崩潰,某些功能暫時不可用
不一樣點:服務熔斷通常是下游服務故障致使的,而服務降級通常是從服務負載考慮,由調用方控制
自我修復其實就是斷路器狀態的切換,斷路器打開(熔斷)後5min內的請求都快速失敗;5min後斷路器半開,放行部分請求,
若是這些請求(服務調用)都成功了,說明問題已修復,關閉斷路器,鏈路恢復通行;不然繼續下一個5min。
5min是窗口期,數值能夠調。
Hystrix是在消費者(調用方)中使用的,通常要和Feign搭配使用
(1)在建立消費者時勾選Spring Cloud Circuit Breaker -> Hystrix [Maintenance]
也能夠手動加hystrix的依賴:
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-netflix-hystrix</artifactId> </dependency>
(2)引導類上加 @EnableCircuitBreaker或@EnableHystrix
@EnableHystrix中包含了@EnableCircuitBreaker這個註解
(3)在controller中設置回退方法
@Controller @RequestMapping("/api/v1/user") public class UserController { @Resource // private RestTemplate restTemplate; private OrderFeignService orderFeignService; @RequestMapping("order/{user_id}") @ResponseBody @HystrixCommand(fallbackMethod = "findOrdersByUserIdFail") //指定回退方法 public Map<String,Object> findOrdersByUserId(@PathVariable("user_id") Integer userId){ //調用服務 // List<Order> orders = restTemplate.getForObject("http://order-service/api/v1/order/list/" + userId, List.class); List<Order> orders = orderFeignService.findOrdersByUserId(userId); HashMap<String, Object> map = new HashMap<>(); map.put("code", 0); map.put("data", orders); return map; } /** * 回退方法,回退方法命名通常是原方法名+Fail */ public Map<String,Object> findOrdersByUserIdFail(Integer userId){ //參數:遠程服務接口,返回值類型(目標類型) HashMap<String, Object> map = new HashMap<>(); map.put("code", -1); map.put("msg", "人太多了,你被擠出來了,請稍後重試"); return map; } }
Hystrix通常是在controller中設置的,也能夠在其它地方進行設置。但服務調用要寫在service層、而後在controller中調用service層,我這裏圖方便直接在controller中調用服務。
使用Feign、RestTemplate調用服務均可以。
返回的時候通常用map裝載數據,code表示處理狀況,前端或上游服務根據碼值肯定處理的狀況,進行對應的數據展現。
好比code=xx表示處理成功了,若是是數據查詢,用表格仍是什麼把獲取的數據展現出來;若是code=xx表示處理失敗,用提示框告訴用戶失敗了。
固然回退方法能夠直接返回null,若是返回null,前端、上游服務處理返回結果時須要先判斷返回的數據是否爲null。
@HystrixCommand(fallbackMethod = "findOrdersByUserIdFail")標註在某個方法上,只對該方法有效;
@DefaultProperties(defaultFallback = "findOrdersByUserIdFail")標註在類上,對類中全部的方法都有效,該類中的某個方法執行失敗時,都會調用默認的回退方法來代替。
上面的方式使用的是單獨的Hystrix,也可使用Feign內置的Hystrix。
一樣是在消費中使用的,建立消費者時不須要勾選Hystrix,不須要添加Hystrix的依賴,由於Feign的依賴中已經包含了Hystrix。
在引導類中不須要使用Hystrix的註解
@EnableFeignClients // @EnableHystrix
// 或者@EnableCircuitBreaker
(1)在配置文件中開啓feign自帶的hystrix
feign: hystrix: enabled: true
默認是false,須要手動開啓
(2)寫一個類實現Feign接口,和Feign接口放在同一個包下
@Component //放到spring容器中 public class OrderFeignServiceFallback implements OrderFeignService { //實現的方法就是接口中對應方法的回退方法 @Override public List<Order> findOrdersByUserId(Integer user_id) { return null; } }
(3)在Feign接口中指定對應的回退類
@FeignClient(name = "order-service", fallback = OrderFeignServiceFallback.class) public interface OrderFeignService { @GetMapping("/api/v1/order/list") List<Order> findOrdersByUserId(@RequestHeader("user_id") Integer user_id); }
使用時不須要使用 @HystrixCommand 指定回退方法,調用失敗時會自動執行回退類中對應的回退方法。
第一種在哪裏使用都行,能夠給controller、service、dao或者其餘地方的方法指定回退方法,哪一個方法均可以加回退方法;
第二種只是給服務調用加回退方法,只做用於服務調用的語句。
第一種可使用RestTemplate或者Feign,第二種只能使用Feign。
總之第二種的使用範圍頗有限,只能對Feign方式的服務調用起到容錯保護;
第一種的使用範圍十分普遍,不侷限於服務調用,可對整個應用起到容錯保護,功能更增強大。
一、通知用戶
有些服務須要一段時候後纔會處理,好比訂單處理,會先放到消息隊列中,逐個處理,
若是處理失敗(服務調用失敗)須要及時通知用戶,比xx分鐘內到帳、xx分鐘內出票,若是服務調用失敗,在回退方法中要通知用戶。
若是是車票、電影票、充話費之類較爲重要的,要在回退方法中記錄日誌,並調用短信接口及時告知用戶出票失敗、充值失敗,退款預計xx小時內到帳。
通知時,若是當前線程還要作一些操做,好比返回數據給上游服務,通知是一個單獨的業務,能夠新建一個線程來通知,不要阻塞當前線程。
二、通知系統管理員、運維
統計服務調用失敗的次數,若是指定時間內服務調用失敗次數達到指定值,或者指定時間內服務調用失敗的比例達到指定值,就以短信或者email的方式通知運維、管理員。
能夠寫一個工具類,用一個靜態變量記錄服務調用總數,調用某服務一次就+1,再使用一個靜態變量統計該服務調用失敗的次數;
寫一個springboot定時任務,好比每5min執行一次,檢測調用總次數、服務調用失敗比例,達到指定值就通知管理員、運維,
檢測調用總次數是爲了確認被調者是否可能出問題了,不能調用總數一、失敗率100%就通知管理員,多是用戶本身的問題。
通知以後或者比例未達到指定值,將統計值清空,從新統計下一個5min。
須要作好日誌記錄,方便管理員找出問題。
好比說被調用的服務集羣掛了,不能每隔5min就通知管理一次,人家都開始處理了,你還一直通知。
能夠在管理面板中提供按鈕,點擊能夠關閉、開啓通知管理員的功能,管理員收到故障通知後在面板中關閉通知管理員的功能,開始排查問題,解決後再開啓通知管理員的功能。
也能夠通知管理員以前先檢測redis上有沒有某個鍵值對,有就說明通知過了,再也不通知;沒有就設置此鍵值對,並指定過時時間,再通知管理員。好比過時時間設置爲2h,2h通知一次。
Hystrix的參數配置能夠寫在@HystrixCommand(標註在方法上,只對該方法有效)、@DefaultProperties(標註在類上,對類中全部的方法都有效)註解中,
但配置天然是寫在配置文件中好些,官方也是寫在配置文件中的。
Hystrix的配置是寫在消費者中的,經常使用配置以下:
hystrix: command: default: execution: #是否啓用超時,默認true,通常都是設置爲true #timeout: #enabled: true isolation: #有2種隔離策略:THREAD 線程池(默認)、SEMAPHORE 信號量 strategy: THREAD thread: #超時時間,默認1000,ms timeoutInMilliseconds: 4000 #semaphore: #設置信號量最大值,默認10 #maxConcurrentRequests: 100
上面使用的是hystrix,參數前綴是hystrix ;若是使用feign自帶的hystrix,參數前綴是 feign: hystrix
超時時間指的是@HystrixCommand標註的方法執行的時間,若是使用的是Feign自帶的Hystrix,指定的是服務調用的時間。
超時自動返回失敗,若是將超時時間關閉,則一直等待服務調用完成,不會超時。通常都開啓超時時間。
隔離策略即服務限流,消費者通常都會對提供者發起多個服務調用請求,消費者能夠設置服務限流,限制自己對提供者的併發請求數。有2種策略
(1)THREAD 線程池,也叫作線程隔離,默認的隔離策略
爲每一個被調用的服務都建立一個線程池,將每一個服務調用請求都包裝爲一個線程,放到線程池中。
線程池中的服務調用請求都是正在執行的,若線程池滿了,放在隊列中排隊等待,若隊列也滿了,則後續對該被調者的請求直接快速失敗。
Hystrix使用的是jdk自帶的線程池,不是tomcat的線程池。併發執行的服務調用數取決於線程池能容納的線程數。
(2)SEMAPHORE 信號量
信號量便可同時處理的請求個數,默認值10。
調用一次該服務,將信號量-1,一個調用請求結束將信號量+1,信號量爲0時再也不接受對該服務的調用請求,直接快速失敗。
信號量適用於高併發服務調用,好比每秒數千次服務調用,由於使用線程池會致使線程池中同時存在幾千個線程,開銷巨大。
不用將服務調用請求包裝爲單獨的線程,速度更快,但信號量通常只用於非網絡調用。
快速失敗是指不調用服務提供者,直接服務降級,執行回退方法。
若是要設置Hystrix的更多參數:
github上搜hystrix找到官方 -> WiKi -> 點擊右側的目錄中的Configuration便可查看hystrix所有參數的介紹