Hystrix熔斷原理與實(shí)踐

hystrix.png

技術(shù)需求點(diǎn):

在SpringCloud+SpringBoot部署的微服務(wù)系統(tǒng)中,模擬服務(wù)故障,證明Hystrix組件可以保證當(dāng)服務(wù)提供者提供的服務(wù)不可用時(shí),調(diào)用方可以切換到降級(jí)后的執(zhí)行策略晌端,保持系統(tǒng)服務(wù)穩(wěn)定性,同時(shí)介紹Hystrix的算法機(jī)制和原理恬砂。

Hystrix是一種叫豪豬的動(dòng)物咧纠,身體后半部分長(zhǎng)滿了圓棘刺,當(dāng)遇到危險(xiǎn)時(shí)泻骤,通過后退的攻擊方式將棘刺插入敵人身體漆羔,以保護(hù)自己不受傷害。

前言:分布式系統(tǒng)服務(wù)雪崩問題

在分布式系統(tǒng)中狱掂,多個(gè)服務(wù)之間通常是通過Rpc遠(yuǎn)程調(diào)用的方式實(shí)現(xiàn)的演痒,這種服務(wù)依賴的模式可能會(huì)帶來問題,如果被依賴的服務(wù)A掛掉趋惨,而調(diào)用者B沒采取任何防御措施鸟顺,可能會(huì)導(dǎo)致調(diào)用者B的所有線程在數(shù)秒內(nèi)處于阻塞狀態(tài)釋放不了,后續(xù)請(qǐng)求累積增加器虾,可能導(dǎo)致調(diào)用者B癱瘓讯嫂,服務(wù)B癱瘓又會(huì)導(dǎo)致B的調(diào)用者C癱瘓......最后引起服務(wù)雪崩問題。因此兆沙,一定的防御措施(降級(jí)策略)需要在系統(tǒng)設(shè)計(jì)時(shí)考慮到欧芽,當(dāng)服務(wù)調(diào)用方發(fā)現(xiàn)提供方的服務(wù)出現(xiàn)異常時(shí),調(diào)用方能夠快速切換到預(yù)置好的降級(jí)策略中葛圃。

正常時(shí)千扔,調(diào)用者(UserRequest)調(diào)用Dependency A、H库正、I曲楚、P服務(wù):


圖片來源參考文章3.png

當(dāng)Dependcency I系統(tǒng)出現(xiàn)問題,調(diào)用者UserRequest也會(huì)阻塞:


圖片來源參考文章3.png

在請(qǐng)求量較大時(shí)诀诊,在數(shù)秒內(nèi)所有線程會(huì)阻塞洞渤,導(dǎo)致所有資源飽和,系統(tǒng)無法再提供服務(wù)属瓣。


圖片來源參考文章3.png

一.Hystrix基于自反饋調(diào)節(jié)熔斷狀態(tài)的算法原理

在電路系統(tǒng)中载迄,會(huì)有保險(xiǎn)絲,當(dāng)電流過大產(chǎn)熱過大時(shí)抡蛙,保險(xiǎn)絲會(huì)熔斷以切斷與外部電路的聯(lián)通护昧。Hystrix充當(dāng)了保險(xiǎn)絲的角色,當(dāng)請(qǐng)求量過大且請(qǐng)求錯(cuò)誤量超過我們?cè)O(shè)定的閾值時(shí)粗截,Hystrix的熔斷器會(huì)熔斷惋耙,讓調(diào)用者服務(wù)自動(dòng)降級(jí)以保護(hù)服務(wù)。自動(dòng)降級(jí)后的服務(wù)不會(huì)再遠(yuǎn)程調(diào)用依賴方的服務(wù),轉(zhuǎn)向我們的降級(jí)策略去執(zhí)行绽榛,比如給個(gè)失敗頁面快速失敗湿酸,減少調(diào)用方的漫長(zhǎng)等待。

此外灭美,熔斷開啟推溃,服務(wù)降級(jí)后,Hystrix有自動(dòng)恢復(fù)的功能届腐,假如我們?cè)O(shè)定每次熔斷后休眠5秒鐘(5秒鐘內(nèi)不調(diào)用遠(yuǎn)程服務(wù))铁坎,到時(shí)間后會(huì)自動(dòng)重試,讓20次請(qǐng)求嘗試調(diào)用遠(yuǎn)程服務(wù)犁苏,如果能返回正常結(jié)果硬萍,就認(rèn)為服務(wù)恢復(fù)正常,熔斷器自動(dòng)關(guān)閉围详,服務(wù)降級(jí)停止朴乖。

根據(jù)這一過程,Hystrix的狀態(tài)機(jī)分為三種狀態(tài):open助赞、closed寒砖、half-open,熔斷器會(huì)在這三種狀態(tài)之間切換嫉拐。具體來講:

  • open:被調(diào)用方在一定時(shí)間窗內(nèi)請(qǐng)求錯(cuò)誤率大于設(shè)定的閾值,被判定為異常魁兼,熔斷開啟婉徘,服務(wù)降級(jí),調(diào)用方執(zhí)行本地的降級(jí)策略咐汞,不進(jìn)行遠(yuǎn)程調(diào)用盖呼;
  • closed:被調(diào)用服務(wù)正常,熔斷關(guān)閉化撕,調(diào)用方遠(yuǎn)程調(diào)用服務(wù)几晤。
  • half-open:嘗試的中間狀態(tài),調(diào)用方熔斷且在休眠了一段時(shí)間后植阴,調(diào)用方發(fā)起測(cè)試性的遠(yuǎn)程調(diào)用蟹瘾,測(cè)試被調(diào)用者是否正常。

熔斷器的開關(guān)狀態(tài)取決于HystrixCommandMetrics對(duì)象里面的數(shù)據(jù)掠手,該對(duì)象存儲(chǔ)了類似遠(yuǎn)程接口調(diào)用次數(shù)憾朴,失敗次數(shù)等數(shù)據(jù),以時(shí)間窗口的形式統(tǒng)計(jì)各維度數(shù)據(jù)喷鸽。

二.模擬Hystrix實(shí)戰(zhàn)

1.pom依賴

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
        </dependency>

2.開啟Hystrix
在EurekaApplication文件上添加注解@EnableCircuitBreaker開啟熔斷

@EnableCircuitBreaker//開啟熔斷
@EnableEurekaClient//開啟Eureka客戶端
@SpringBootApplication
@EnableFeignClients//開啟Feign客戶端
public class EurekaApplication {
    public static void main(String[] args) {
        SpringApplication.run(EurekaApplication.class,args);
    }
}

添加之后众雷,感覺注解越來越多,因此可以合并下。
首先將@EnableEurekaClient替換成@EnableDiscoveryClient砾省,兩者的共同點(diǎn)是:都能讓注冊(cè)中心發(fā)現(xiàn)自己的服務(wù)鸡岗,區(qū)別是@EnableEurekaClient只支持Eureka作為注冊(cè)中心,而@EnableDiscoveryClient支持其它注冊(cè)中心编兄,比如consul轩性。
然后將@EnableCircuitBreaker、@EnableEurekaClient翻诉、@SpringBootApplication替換成@SpringCloudApplication炮姨,看@SpringCloudApplication的代碼可以看出,該注解就是集成了前面三個(gè)碰煌。

image.png

3.調(diào)用者接口
對(duì)getUsers()方法進(jìn)行熔斷舒岸,需要給這個(gè)方法寫一個(gè)對(duì)應(yīng)的fallback方法,當(dāng)調(diào)用提供者服務(wù)出現(xiàn)異常時(shí)芦圾,Hystrix會(huì)自動(dòng)執(zhí)行fallback的方法蛾派。當(dāng)然,需要給方法指定熔斷方法个少,用@HystrixCommand注解聲明洪乍,
(如果想給類的所有方法都指定一個(gè)熔斷方法夜焦,使用@DefaultProperties(defaultFallback="getUsersFallback")壳澳,需要熔斷的方法再加@HystrixCommand才行)。注解里面還可以進(jìn)行各種Hystrix的配置茫经,例如熔斷時(shí)間等等巷波,下面再說。

@RestController
public class UserController {

    @Autowired
    private UserFeignService userFeignService;

    @RequestMapping("/consumer")
    @HystrixCommand(fallbackMethod = "getUsersFallback")
    public String getUsers(){
        return userFeignService.getUsers();
    }

    public String getUsersFallback(){
        return "調(diào)用的服務(wù)出現(xiàn)異常了";
    }
}

其中卸伞,UserFeignService的代碼如下:

//開啟feign客戶端抹镊,eureka-provider-user微服務(wù)的serviceid(唯一)
@FeignClient("eureka-provider")
public interface UserFeignService {

    @RequestMapping("/user")
    public String getUsers();
}

4.被調(diào)用者接口

@RestController
public class UserController {

    @RequestMapping("/user")
    public String getUsers(){
        return "provider的User服務(wù)";
    }
}

完整的基于Eureka注冊(cè)中心的微服務(wù)搭建過程,請(qǐng)參考SpringCloud+SpringBoot搭建服務(wù)注冊(cè)與調(diào)用平臺(tái)這篇文章荤傲。

5.測(cè)試結(jié)果
當(dāng)consumer能正常調(diào)用provider服務(wù)時(shí)垮耳,


image.png

此時(shí),停掉provider服務(wù)遂黍,再次調(diào)用:


image.png

說明熔斷成功终佛,重啟provider服務(wù),又可以正常調(diào)用了雾家。

6.將熔斷放在service層級(jí)
上面的熔斷方法我們是放在controller層級(jí)的查蓉,但這給業(yè)務(wù)帶來了極大的耦合,我們希望把service層就提供了熔斷服務(wù)榜贴,controller層只調(diào)用即可豌研,出現(xiàn)異常在service層處理掉妹田。我們使用feign組件發(fā)起遠(yuǎn)程調(diào)用, 因此鹃共,在使用feign組件基礎(chǔ)上鬼佣,我們這樣優(yōu)化:
(1)先創(chuàng)建一個(gè)實(shí)現(xiàn)類UserFeignFallback implements UserFeignService,

@Component
public class UserFeignFallback implements UserFeignService {

    @Override
    public String getUsers() {
        return "Service層:調(diào)用的服務(wù)出現(xiàn)異常了";
    }
}

(2)在UserFeignService指定fallback的方法:

@FeignClient(value="eureka-provider",fallback = UserFeignFallback.class)
public interface UserFeignService {

    @RequestMapping("/user")
    public String getUsers();
}

(3)在配置文件中開啟feign的hystrix熔斷功能:

feign.hystrix.enabled=true

(4)最后把controller的接口改成普通的調(diào)用接口即可:

    @RequestMapping("/consumer")
    public String getUsers(){
        return userFeignService.getUsers();
    }

三.什么情況下會(huì)觸發(fā)fallback方法霜浴?

引自參考4

事件 描述 觸發(fā)fallback
EMIT 值傳遞 NO
SUCCESS 執(zhí)行完成晶衷,沒有錯(cuò)誤 NO
FAILURE 執(zhí)行拋出異常 YES
TIMEOUT 執(zhí)行開始,但沒有在允許的時(shí)間內(nèi)完成 YES
BAD_REQUEST 執(zhí)行拋出HystrixBadRequestException NO
SHORT_CIRCUITED 斷路器打開阴孟,不嘗試執(zhí)行 YES
THREAD_POOL_REJECTED 線程池拒絕晌纫,不嘗試執(zhí)行 YES
SEMAPHORE_REJECTED 信號(hào)量拒絕,不嘗試執(zhí)行 YES

四.Hystrix可以配置哪些參數(shù)

配置方式有2種永丝,一個(gè)是在注解@HystrixCommand屬性里面配置(比較麻煩)锹漱,一個(gè)是在配置文件中配置,兩種都可以慕嚷,但在注解中配置的優(yōu)先級(jí)更高哥牍,下面是一些常用的配置

  • 超時(shí)時(shí)間(默認(rèn)1000ms,單位:ms)
    1.hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds
    調(diào)用者的配置文件中配置喝检,調(diào)用者所有方法的超時(shí)時(shí)間都是該值
    2.hystrix.command.HystrixCommandKey.execution.isolation.thread.timeoutInMilliseconds
    調(diào)用者的指定方法中配置嗅辣,優(yōu)先級(jí)高于上邊的全局配置

  • 統(tǒng)計(jì)次數(shù)
    circuitBreaker.requestVolumeThreshold
    當(dāng)在配置時(shí)間窗口內(nèi)達(dá)到此數(shù)量的失敗后,進(jìn)行熔斷挠说,默認(rèn)20個(gè)

  • close休眠試間
    circuitBreaker.sleepWindowInMilliseconds
    熔斷多久后開始嘗試是否恢復(fù)澡谭,默認(rèn)5s

  • 出錯(cuò)百分比,
    circuitBreaker.errorThresholdPercentage
    當(dāng)錯(cuò)誤超過該百分比觸發(fā)熔斷损俭,默認(rèn)50%

  • 線程池核心線程數(shù)
    hystrix.threadpool.default.coreSize(默認(rèn)為10)

后記:Hystrix現(xiàn)狀-官方社區(qū)已死

Hystrix官網(wǎng)已經(jīng)不再維護(hù)新版本译暂,但是因?yàn)槠浒姹据^為穩(wěn)定,現(xiàn)階段不影響用戶對(duì)它的正常使用撩炊。Hystrix的替代方案有兩個(gè):
1.Alibaba Sentinel
Sentinel在阿里內(nèi)部已經(jīng)被大規(guī)模采用,非常穩(wěn)定崎脉,目前在Spring Cloud的孵化器項(xiàng)目Spring Cloud Alibaba中拧咳,是阿里開源的一款斷路器實(shí)現(xiàn)。

2.Resilience4J
Resilience4J是Hystrix官方推薦的替代方案囚灼,是一款輕量級(jí)框架骆膝,使用簡(jiǎn)單,并且文檔非常清晰灶体、豐富阅签。

Tips:現(xiàn)在我們?cè)賮砜春镭i這種動(dòng)物,是不是跟hystrix的機(jī)制原理一模一樣蝎抽,當(dāng)發(fā)現(xiàn)各種服務(wù)故障(敵人)時(shí)政钟,調(diào)用fallback方法(倒退)快速失敗,提高系統(tǒng)抵御災(zāi)害能力,作者不但寫出了這么強(qiáng)大的組件养交,還命名了這么貼切的名字精算,膜拜!

參考文章:
參考1碎连,原理簡(jiǎn)介:http://www.reibang.com/p/b8d3eb0cf721?utm_source=oschina-app
參考2灰羽,源碼解析:http://www.reibang.com/p/684b04b6c454
參考3,Hystrix介紹:https://www.cnblogs.com/cjsblog/p/9391819.html
參考4鱼辙,詳細(xì)屬性配置:https://blog.csdn.net/tongtong_use/article/details/78611225

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末廉嚼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子倒戏,更是在濱河造成了極大的恐慌怠噪,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,222評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件峭梳,死亡現(xiàn)場(chǎng)離奇詭異舰绘,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)葱椭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,455評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門捂寿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人孵运,你說我怎么就攤上這事秦陋。” “怎么了治笨?”我有些...
    開封第一講書人閱讀 157,720評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵驳概,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我旷赖,道長(zhǎng)顺又,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,568評(píng)論 1 284
  • 正文 為了忘掉前任等孵,我火速辦了婚禮稚照,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘俯萌。我一直安慰自己果录,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,696評(píng)論 6 386
  • 文/花漫 我一把揭開白布咐熙。 她就那樣靜靜地躺著弱恒,像睡著了一般。 火紅的嫁衣襯著肌膚如雪棋恼。 梳的紋絲不亂的頭發(fā)上返弹,一...
    開封第一講書人閱讀 49,879評(píng)論 1 290
  • 那天锈玉,我揣著相機(jī)與錄音,去河邊找鬼琉苇。 笑死嘲玫,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的并扇。 我是一名探鬼主播去团,決...
    沈念sama閱讀 39,028評(píng)論 3 409
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼穷蛹!你這毒婦竟也來了土陪?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,773評(píng)論 0 268
  • 序言:老撾萬榮一對(duì)情侶失蹤肴熏,失蹤者是張志新(化名)和其女友劉穎鬼雀,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體蛙吏,經(jīng)...
    沈念sama閱讀 44,220評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡源哩,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,550評(píng)論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了鸦做。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片励烦。...
    茶點(diǎn)故事閱讀 38,697評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泼诱,靈堂內(nèi)的尸體忽然破棺而出坛掠,到底是詐尸還是另有隱情,我是刑警寧澤治筒,帶...
    沈念sama閱讀 34,360評(píng)論 4 332
  • 正文 年R本政府宣布屉栓,位于F島的核電站,受9級(jí)特大地震影響耸袜,放射性物質(zhì)發(fā)生泄漏友多。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,002評(píng)論 3 315
  • 文/蒙蒙 一堤框、第九天 我趴在偏房一處隱蔽的房頂上張望域滥。 院中可真熱鬧,春花似錦胰锌、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,782評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至荆忍,卻和暖如春格带,著一層夾襖步出監(jiān)牢的瞬間撤缴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,010評(píng)論 1 266
  • 我被黑心中介騙來泰國打工叽唱, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留屈呕,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,433評(píng)論 2 360
  • 正文 我出身青樓棺亭,卻偏偏與公主長(zhǎng)得像虎眨,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子镶摘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,587評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容