本篇文章為Spring Cloud 各模塊演示代碼的分支[Hystrix]部分贱呐。
先從幾個(gè)概念開(kāi)始,了解概念有助于對(duì)Hystrix的理解脯颜。
熔斷虽画、降級(jí)舞蔽、限流的概念
-
雪崩效應(yīng)
分布式系統(tǒng)中經(jīng)常會(huì)出現(xiàn)某個(gè)基礎(chǔ)服務(wù)不可用造成整個(gè)系統(tǒng)不可用的情況, 這種現(xiàn)象被稱為服務(wù)雪崩效應(yīng). 為了應(yīng)對(duì)服務(wù)雪崩, 一種常見(jiàn)的做法是手動(dòng)服務(wù)降級(jí).-
定義
雪崩效應(yīng):服務(wù)提供者 的不可用導(dǎo)致 服務(wù)調(diào)用者 的不可用,并將不可用 逐漸放大 的過(guò)程
下圖從上到下看,可以發(fā)現(xiàn)隨著A不可用码撰,慢慢的B服務(wù)還有CD服務(wù)都不可用了渗柿。 雪崩效應(yīng)形成的原因
我把服務(wù)雪崩的參與者簡(jiǎn)化為 服務(wù)提供者 和 服務(wù)調(diào)用者, 并將服務(wù)雪崩產(chǎn)生的過(guò)程分為以下三個(gè)階段來(lái)分析形成的原因:
1.服務(wù)提供者不可用
2.重試加大流量
3.服務(wù)調(diào)用者不可用
服務(wù)提供者不可用原因
服務(wù)雪崩的每個(gè)階段都可能由不同的原因造成, 比如造成 服務(wù)不可用的原因有:
硬件故障: 硬件故障可能為硬件損壞造成的服務(wù)器主機(jī)宕機(jī), 網(wǎng)絡(luò)硬件故障造成的服務(wù)提供者的不可訪問(wèn).
程序Bug
緩存擊穿: 緩存擊穿一般發(fā)生在緩存應(yīng)用重啟, 所有緩存被清空時(shí),以及短時(shí)間內(nèi)大量緩存失效時(shí). 大量的緩存不命中, 使請(qǐng)求直擊后端,造成服務(wù)提供者超負(fù)荷運(yùn)行,引起服務(wù)不可用.
用戶大量請(qǐng)求: 在秒殺和大促開(kāi)始前,如果準(zhǔn)備不充分,用戶發(fā)起大量請(qǐng)求也會(huì)造成服務(wù)提供者的不可用.重試加大流量
用戶重試:在服務(wù)提供者不可用后, 用戶由于忍受不了界面上長(zhǎng)時(shí)間的等待,而不斷刷新頁(yè)面甚至提交表單.
代碼邏輯重試:服務(wù)調(diào)用端的會(huì)存在大量服務(wù)異常后的重試邏輯.服務(wù)調(diào)用者不可用
當(dāng)服務(wù)調(diào)用者使用 同步調(diào)用 時(shí), 會(huì)產(chǎn)生大量的等待線程占用系統(tǒng)資源. 一旦線程資源被耗盡,服務(wù)調(diào)用者提供的服務(wù)也將處于不可用狀態(tài), 于是服務(wù)雪崩效應(yīng)產(chǎn)生了.
-
應(yīng)對(duì)策略
熔斷:通過(guò) 超時(shí)機(jī)制使得不可用服務(wù)的調(diào)用快速失敗
限流:網(wǎng)關(guān)限流、用戶交互限流灸拍、關(guān)閉重試做祝、接口限流砾省。在JAVA中實(shí)現(xiàn)接口限流可以用guava的RateLimiter鸡岗,它實(shí)現(xiàn)了令牌桶算法和漏桶算法。
降級(jí):調(diào)用服務(wù)線程池隔離编兄、依賴服務(wù)分類(終止弱依賴服務(wù))
服務(wù)自動(dòng)擴(kuò)容
以上概念部分摘自 http://kaimingwan.com/post/jia-gou/shi-yong-hystrixwan-cheng-rong-duan-xian-liu-he-jiang-ji
Hystrix 代碼示例
- 斷路器demo
1. 啟動(dòng)注冊(cè)中心eureka-a
2.啟動(dòng)服務(wù)端spring-cloud-03-hystrix-client
3.啟動(dòng)客戶端spring-cloud-03-hystrix-request-a
請(qǐng)求超時(shí)觸發(fā):http://localhost:6001/hystrix-hello
返回:----------執(zhí)行降級(jí)策略------------
異常捕捉觸發(fā): http://localhost:6001/hystrix-handler/** * 配置的斷路時(shí)間為2秒,但是調(diào)用的服務(wù)睡眠了3秒轩性。進(jìn)入降級(jí)策略 * @return */ @HystrixCommand(fallbackMethod = "callHelloFailback") public String callHello() { return restTemplate.getForObject("http://client-service/hello", String.class); } public String callHelloFailback(){ System.err.println("----------執(zhí)行降級(jí)策略------------"); return "----------執(zhí)行降級(jí)策略------------"; }
返回:獲取異常信息并可以做具體的降級(jí)處理
單獨(dú)API配置:/** * 異常捕獲方式的斷路器 */ @HystrixCommand(fallbackMethod = "handlerFailback", ignoreExceptions = {BadRequestException.class}) public String handler() { throw new RuntimeException("運(yùn)行時(shí)異常..."); } /** * 異常信息可傳遞到fallback方法中 */ public String handlerFailback(Throwable e){ System.err.println("異常信息: " + e.getMessage()); return "獲取異常信息并可以做具體的降級(jí)處理"; }
/** * 對(duì)單獨(dú)API 配置斷路由規(guī)則,不受配置文件中的配置參數(shù)影響 * 如下,配置8秒讀取超時(shí),配置文件中的2秒將失效 * 更多commandProperties信息:https://github.com/Netflix/Hystrix/wiki/Configuration */ @HystrixCommand( commandKey = "hiKey", commandProperties = {@HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", /*KEY*/ value = "8000" /*VALUE*/)}, fallbackMethod = "callHiFailback") public String callhi() { System.err.println("--客戶端調(diào)用-----"); return restTemplate.getForObject("http://client-service/hi", String.class); } public String callHiFailback(){ System.err.println("----------執(zhí)行降級(jí)策略------------"); return "----------執(zhí)行降級(jí)策略------------"; }
Hystrix DashBoard 服務(wù)壓力查看器
1.在以上的Demo啟動(dòng)的基礎(chǔ)上,啟動(dòng) spring-cloud-03-hystrix-dashboard
2.訪問(wèn) http://localhost:5001/hystrix
3.點(diǎn)擊進(jìn)入后可查看所有的請(qǐng)求情況
Hystrix Turbine 集群服務(wù)壓力查看器
1.在以上的基礎(chǔ)上啟動(dòng) spring-cloud-03-hystrix-request-b
和 集群收集模塊turbine spring-cloud-03-hystrix-turbine
這時(shí)在dashboard中填入的地址為http://localhost:3000/turbine.stream
點(diǎn)擊監(jiān)控狠鸳。分別請(qǐng)求 spring-cloud-03-hystrix-request-a
和 spring-cloud-03-hystrix-request-b
的API之后揣苏。會(huì)發(fā)現(xiàn)在監(jiān)控平臺(tái)上的Hosts變?yōu)榱?.兩個(gè)客戶端的請(qǐng)求都能被監(jiān)控了悯嗓。
END