1.3.1 Hystrix 簡單介紹
hystrix 是netfix 公司開發(fā)的防止服務雪崩的短路裝置,增加我們服務的容錯能力,
服務雪崩:在微服務的系統(tǒng)中,大部分服務被拆分為多個單元,然后通過RPC或者HTTP進行調(diào)用,假如其中某個服務出現(xiàn)故障,同時我們設置了對應的服務超時和重試機制會導致請求堆積,假如不能及時處理可能會使得整個系統(tǒng)崩潰,所以我們需要一種裝置能在服務不可用的時候能將該服務隔離,并且能在一段時間后重試,假如服務可用,則短路器斷開,該服務節(jié)點重新提供服務。
如圖是Hystrix的整體流程圖

image.png
- CommondKey
Hystrix使用命令模式 HystrixCommand(Command) 包裝依賴調(diào)用邏輯,每個命令在單獨線程中/信號授權下執(zhí)行。CommondKey 有下面4個方法。
- excute 阻塞等待返回結(jié)果或者拋錯。
- queue 返回一個future ,通過future 拿結(jié)果。
- observe 返回一個observable對象 (soul 就是使用這種方式)observable對象源于RxJava ,我們可以通過observable 監(jiān)聽到完成事件,錯誤事件和成功事件。
- toObservable 返回一個Observable,當監(jiān)聽該Observable后hystrix命令將會執(zhí)行并返回結(jié)果。
- cache 查看是否命中緩存,在Hystrix 中我們可以設置緩存,讓相同的commandKey直接返回上一次結(jié)果。
- HystrixCircuitBreaker
整個是整個 Hystrix 的核心功能,其狀態(tài)圖如圖所示,有三個狀態(tài),OPEN 即處于熔斷打開狀態(tài),CLOSE 處于關閉狀態(tài),HALF_OPEN 半開狀態(tài),HALF_OPEN 和 OPEN 這兩個狀態(tài)存在著相互轉(zhuǎn)換的關系,比如soul中設置跳閘休眠時間,在超過該時間后就會觸發(fā)OPEN狀態(tài)向HALF_OPEN 轉(zhuǎn)移,但HALF_OPEN 還沒達到關閉跳閘的條件又會重新轉(zhuǎn)為 OPNE 狀態(tài)。

image.png
- semaphore OR ThreadPool
Hystrix 對服務的隔離有兩種方式一種是線程池,一種是信號量。
- 線程池:線程池是 Hystrix 默認的隔離模式,Hystrix為不同的服務都創(chuàng)建獨立的線程池。
- 信號量:使用信號量標志不同服務的狀態(tài)。
1.3.2 修改服務設置故障
我們先將之前準備的SpringCloud工程進行修改,隨機睡眠10s。
/**
* Find by id order dto.
*
* @param id the id
* @return the order dto
*/
@GetMapping("/findById")
@SoulSpringCloudClient(path = "/findById")
public OrderDTO findById(@RequestParam("id") final String id) throws InterruptedException {
OrderDTO orderDTO = new OrderDTO();
orderDTO.setId(id);
orderDTO.setName("hello world spring cloud findById");
Random random = new Random();
if (random.nextInt(10) > 2) {
Thread.sleep(10 * 1000);
}
return orderDTO;
}
1.3.3 soul 相關配置
我們需要在soul-admin啟動Hystrix 插件,并定義它的selector 和 selector的規(guī)則。

image.png
這里我們先配置selector ,設置路徑為/Springcloud/**。

image.png
然后設置具體規(guī)則,我們這里定義/springcloud/order/findById 為匹配規(guī)則路徑,Hystrix 的使用信號量的方式進行服務熔斷,Hystrix的comondGroup 使用Context-path,Hystrix的CommondKey 使用我們匹配的路徑,Hystrix的跳閘休眠時間為5s,即5s后重試,這里沒有設置降級的策略,可以自定義一個Mock result 返回,還有這里定義錯誤率超過20%觸發(fā)熔斷。

image.png
接著我們請求服務結(jié)果如下:
mac@AndydeMacBook-Pro ~ curl http://localhost:9195/springcloud/order/findById\?id\=1
{"code":500,"message":"Internal Server Error","data":"/springcloud/order/findById timed-out and fallback failed."}% mac@AndydeMacBook-Pro ~ curl http://localhost:9195/springcloud/order/findById\?id\=1
{"code":500,"message":"Internal Server Error","data":"/springcloud/order/findById short-circuited and fallback failed."}% mac@AndydeMacBook-Pro ~ curl http://localhost:9195/springcloud/order/findById\?id\=1
{"code":500,"message":"Internal Server Error","data":"/springcloud/order/findById short-circuited and fallback failed."}% mac@AndydeMacBook-Pro ~ curl http://localhost:9195/springcloud/order/findById\?id\=1
{"code":500,"message":"Internal Server Error","data":"/springcloud/order/findById short-circuited and fallback failed."}% mac@AndydeMacBook-Pro ~ curl http://localhost:9195/springcloud/order/findById\?id\=1
{"code":500,"message":"Internal Server Error","data":"/springcloud/order/findById short-circuited and fallback failed."}% mac@AndydeMacBook-Pro ~ curl http://localhost:9195/springcloud/order/findById\?id\=1
{"code":500,"message":"Internal Server Error","data":"/springcloud/order/findById short-circuited and fallback failed."}% mac@AndydeMacBook-Pro ~ curl http://localhost:9195/springcloud/order/findById\?id\=1
{"code":500,"message":"Internal Server Error","data":"/springcloud/order/findById timed-out and fallback failed."}% mac@AndydeMacBook-Pro ~
我們先看第一次請求,這里直接請求到SpringCloud服務,然后time-out,這是我們預期的結(jié)果,接著請求就觸發(fā)了熔斷 short-circuited(我們沒有配置follback,所以不會降級服務而是直接熔斷)。我們連續(xù)請求,看最后一次請求結(jié)果,又發(fā)生了超時,這代表我們的請求又到了后面SpringCloud的服務。