Spring Cloud Hystrix 服務(wù)容錯保護的原理實現(xiàn)
一、Hystrix 是什么
在微服務(wù)架構(gòu)中,我們將系統(tǒng)拆分成了若干弱小的單元,單元與單元之間通過HTTP或者TCP等方式相互訪問,各單元的應(yīng)用間通過服務(wù)注冊與訂閱的方式相互依賴。由于每個單元都在不同的進程中運行,依賴 遠程調(diào)用
的方式執(zhí)行,這樣就可能引起因為網(wǎng)速變慢或者網(wǎng)絡(luò)故障導(dǎo)致請求變慢或超時,若此時調(diào)用方的請求在不斷增加,最后就會因等待出現(xiàn)故障的依賴方響應(yīng)形成任務(wù)積壓,最終導(dǎo)致自身服務(wù)的癱瘓。
Hystrix
是Netflix 中的一個組件庫,它隔離了服務(wù)之間的訪問點,阻止了故障節(jié)點之間可能會引起的雪崩效應(yīng),并提供了后備選項。
在微服務(wù)架構(gòu)中,存在著許多的服務(wù)單元,若單一節(jié)點的故障,就很容易因為依賴關(guān)系而引發(fā)故障的蔓延,最終導(dǎo)致整個生態(tài)系統(tǒng)的癱瘓。為了解決這樣的問題,產(chǎn)生了 斷路器
等一系列的保護機制措施。
在 分布式架構(gòu)中
,斷路器模式的作用也是類似的,當某個服務(wù)單元發(fā)生故障(類似用電器發(fā)生短路)之后,通過斷路器的故障監(jiān)控(類似熔斷保險絲),向調(diào)用方返回一個錯誤響應(yīng),而不是長時間的等待。這樣就不會使得線程因調(diào)用故障服務(wù)被長時間占用不釋放,避免了故障在分布式系統(tǒng)中的蔓延。
雪崩效應(yīng)
雪崩效應(yīng)就像是水滴石穿,蝴蝶效應(yīng)一樣,是指微小的事物隨著時間的推移,會變得越來越巨大,從而對整個環(huán)境造成影響的現(xiàn)象。例如:在生態(tài)系統(tǒng)中,某一類物種的滅絕可能對整個生態(tài)系統(tǒng)造成不了太大的損失,但是這類物種的滅絕可能會引發(fā)其他物種的死亡,其他物種的滅絕又會影響另外一種物種的滅亡,就像雪球越滾越大,最終會導(dǎo)致整個生態(tài)系統(tǒng)的崩潰。
如上圖所示:A作為服務(wù)提供者,B為A的服務(wù)消費者,C和D是B的服務(wù)消費者。A不可用引起了B的不可用,并將不可用像滾雪球一樣放大到C和D時,雪崩效應(yīng)就形成了。
雪崩效應(yīng)產(chǎn)生場景
流量激增
: 比如異常流量,用戶重試導(dǎo)致系統(tǒng)負載升高;
緩存刷新
: 假設(shè)A為 client 端,B為 Server 端,假設(shè)A系統(tǒng)請求都流向B系統(tǒng),請求超出了B系統(tǒng)的承載能力,就會造成B系統(tǒng)崩潰
連接未釋放
: 代碼循環(huán)調(diào)用的邏輯問題,資源未釋放引起的內(nèi)存泄漏等問題;
硬件故障
: 比如宕機,機房斷電等
線程同步等待
: 系統(tǒng)間經(jīng)常采用同步服務(wù)調(diào)用模式,核心服務(wù)和非核心服務(wù)共用一個線程池和消息隊列。如果一個核心業(yè)務(wù)線程調(diào)用非核心業(yè)務(wù)線程,這個非核心線程交由第三方系統(tǒng)完成,當?shù)谌较到y(tǒng)本身出現(xiàn)問題,導(dǎo)致核心線程阻塞,一直處于等待狀態(tài),而進程間的調(diào)用是有超時限制的,最終這條線程將斷掉,也可能引發(fā)雪崩;
常見解決方案
針對上述的雪崩問題,每一條都有一個自己的解決方案,但是任何一個解決方案能夠應(yīng)對所有場景
- 針對流量激增,采用自動擴容以應(yīng)對流量激增,或者在負載均衡器上安裝限流模塊
- 針對緩存刷新,參考Cache應(yīng)用的服務(wù)過載案例研究
- 針對硬件故障,采用多機房災(zāi)備,跨機房路由
- 針對同步等待,采用線程隔離,熔斷器等機制
通過實踐發(fā)現(xiàn),線程同步等待是最常見引發(fā)的雪崩效應(yīng)的場景。
二、Hystrix斷路器搭建
在開始使用Spring Cloud Hystrix斷路器之前,我們先用之前實現(xiàn)的一些內(nèi)容作為基礎(chǔ),構(gòu)建一個如下圖所示的服務(wù)調(diào)用關(guān)系:
如圖所示,上面需要的角色有三個,服務(wù)有四個
- ribbon-connsumer: ribbon消費者,消費server-provider提供的服務(wù)
- server-provider: 服務(wù)提供者,提供服務(wù)供消費者消費(有點像父母默默的付出一樣),啟動兩個實例,還記得怎么啟動嗎?—server.port 啟動
- eureka-server: eureka注冊中心,提供最基本的訂閱發(fā)布功能。消費者和服務(wù)提供者都需要往注冊中心注冊自己
依次啟動上面的四個服務(wù),發(fā)現(xiàn)注冊中心已經(jīng)成功注冊了四個服務(wù)(包括自己)
調(diào)用http://localhost:9000/ribbon-consumer 發(fā)現(xiàn)能夠通過Ribbon進行遠端調(diào)用
在未加入斷路器之前,關(guān)閉ribbon-consumer 的連接,再次調(diào)用http://localhost:9000/ribbon-consumer,發(fā)現(xiàn)服務(wù)無法提供(使用Postman 測試)
下面開始引入Hystrix
在ribbon-consumer 工程的pom.xml的dependency節(jié)點下引入spring-cloud-starter-hystrix依賴
在ribbon-consumer 工程的 主加載類
中添加 @EnableCircuitBreaker
開啟斷路器的功能
注意:這里也可以使用@SpringCloudApplication注解來修飾應(yīng)用主類,具體定義如下
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Inherited @SpringBootApplication @EnableDiscoveryClient @EnableCircuitBreaker public @interface SpringCloudApplication {}
SpringCloudApplication 注解上有@EnableCircuitBreaker 注解,用來開啟斷路器的功能,其他主要注解是@SpringBootApplication ,這個注解是SpringBoot的啟動類注解, @EnableDiscoveryClient該注解可以發(fā)現(xiàn)Eureka注冊中心
改造消費方式,新增 HystrixService
類,并且注入 RestTemplate
實例,然后,將在RibbonController中對RestTemplate 的使用遷移到hystrixService方法中,最后,在hystrixService上添加@HystrixCommand注解來指定回掉方法。
// HystrixService @Service public class HystrixService { @Resource RestTemplate restTemplate; // 指定回掉方法是下面的hystrixCallback @HystrixCommand(fallbackMethod = "hystrixCallBack") public String hystrixService(){ return restTemplate.getForEntity("http://server-provider/hystrix",String.class).getBody(); } public String hystrixCallBack(){ return "error"; } }
服務(wù)提供者
的業(yè)務(wù)非常簡單,具體代碼如下
@RequestMapping(value = "/hystrix", method = RequestMethod.GET) public String hystrix(){ return "hystrix"; }
下面來驗證一下通過斷路器的回掉實現(xiàn),重啟之前關(guān)閉的8081端口,恢復(fù)成為四個服務(wù)的狀態(tài),并確保http://localhost:9000/ribbon-consumer/ 能夠提供服務(wù),并且以輪詢的方式循環(huán)訪問8081 和 8082 端口的服務(wù)。此時斷開8081端口,發(fā)現(xiàn)頁面上展示的不再是 hystrix ,而是"error",而另一個服務(wù)是正常能夠打印。
三、斷路器優(yōu)化
經(jīng)過以上服務(wù)的搭建,相信你已經(jīng)能夠搭建出來最基本的Hystrix熔斷器,并且實現(xiàn)了服務(wù)熔斷機制,下面就來對斷路器做一下簡單的優(yōu)化,來模擬 服務(wù)阻塞(長時間未響應(yīng))
的情況。
優(yōu)化 server-provider
代碼如下:
@RequestMapping(value = "/hystrix", method = RequestMethod.GET) public String hystrix() throws InterruptedException { ServiceInstance serviceInstance = discoveryClient.getLocalServiceInstance(); // 讓線程等待幾秒鐘 int sleepTime = new Random().nextInt(3000); Thread.sleep(sleepTime); System.out.println("weak up!!!"); log.info("sleepTime = " + sleepTime); return "hystrix"; }
依次啟動所有的服務(wù),在主頁上訪問 http://localhost:9000/ribbon-consumer ,多次刷新主頁,發(fā)現(xiàn)error 和 hystrix 是交替出現(xiàn)的,這是為何?
因為hystrix斷路器的 默認超時時間
是2000毫秒,所以這里采用了0 - 3000 的隨機數(shù),也就是訪問請求在 0 -2000 毫秒內(nèi)是不超時的,不會觸發(fā)斷路器,而> 2000 毫秒是超市的,默認會觸發(fā)斷路器。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Spring中@PropertySource的使用方法和運行原理詳解
這篇文章主要介紹了Spring中@PropertySource的使用方法和運行原理詳解,PropertySource注解可以方便和靈活的向Spring的環(huán)境容器(org.springframework.core.env.Environment?Environment)中注入一些屬性,這些屬性可以在Bean中使用,需要的朋友可以參考下2023-11-11java中堆內(nèi)存與棧內(nèi)存的知識點總結(jié)
在本篇文章里小編給大家整理的是關(guān)于java中堆內(nèi)存與棧內(nèi)存的知識點總結(jié),有需要的朋友們可以跟著學(xué)習(xí)下。2019-12-12spring Boot查詢數(shù)據(jù)分頁顯示的方法實例
這篇文章主要給大家介紹了關(guān)于spring Boot查詢數(shù)據(jù)分頁顯示的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家學(xué)習(xí)或者使用spring Boot具有一定的參考學(xué)習(xí)價值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-08-08java 判斷一個數(shù)組中的數(shù)值是否連續(xù)相鄰的方法
下面小編就為大家分享一篇java 判斷一個數(shù)組中的數(shù)值是否連續(xù)相鄰的方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-03-03關(guān)于MyBatis plus條件構(gòu)造器的逐條詳解
什么是條件構(gòu)造器呢?簡單來說,條件構(gòu)造器就是用來生成我們查數(shù)據(jù)庫的sql。它可以簡化sql代碼的編寫,靈活、方便且易于維護2021-09-09