Spring Cloud斷路器

在微服務(wù)架構(gòu)中缀拭,我們將系統(tǒng)拆分成了一個個的服務(wù)單元彬犯,各單元間通過服務(wù)注冊與訂閱的方式互相依賴甲捏。由于每個單元都在不同的進程中運行,依賴通過遠程調(diào)用的方式執(zhí)行胁住,這樣就有可能因為網(wǎng)絡(luò)原因或是依賴服務(wù)自身問題出現(xiàn)調(diào)用故障或延遲昧绣,而這些問題會直接導(dǎo)致調(diào)用方的對外服務(wù)也出現(xiàn)延遲珊泳,若此時調(diào)用方的請求不斷增加弥雹,最后就會出現(xiàn)因等待出現(xiàn)故障的依賴方響應(yīng)而形成任務(wù)積壓,最終導(dǎo)致自身服務(wù)的癱瘓缨叫。

舉個例子椭符,在一個電商網(wǎng)站中,我們可能會將系統(tǒng)拆分成耻姥,用戶艰山、訂單、庫存咏闪、積分曙搬、評論等一系列的服務(wù)單元。用戶創(chuàng)建一個訂單的時候鸽嫂,在調(diào)用訂單服務(wù)創(chuàng)建訂單的時候纵装,會向庫存服務(wù)來請求出貨(判斷是否有足夠庫存來出貨)。此時若庫存服務(wù)因網(wǎng)絡(luò)原因無法被訪問到据某,導(dǎo)致創(chuàng)建訂單服務(wù)的線程進入等待庫存申請服務(wù)的響應(yīng)橡娄,在漫長的等待之后用戶會因為請求庫存失敗而得到創(chuàng)建訂單失敗的結(jié)果。如果在高并發(fā)情況之下癣籽,因這些等待線程在等待庫存服務(wù)的響應(yīng)而未能釋放挽唉,使得后續(xù)到來的創(chuàng)建訂單請求被阻塞,最終導(dǎo)致訂單服務(wù)也不可用筷狼。

在微服務(wù)架構(gòu)中瓶籽,存在著那么多的服務(wù)單元,若一個單元出現(xiàn)故障埂材,就會因依賴關(guān)系形成故障蔓延塑顺,最終導(dǎo)致整個系統(tǒng)的癱瘓,這樣的架構(gòu)相較傳統(tǒng)架構(gòu)就更加的不穩(wěn)定俏险。為了解決這樣的問題严拒,因此產(chǎn)生了斷路器模式。

什么是斷路器竖独?

斷路器模式源于Martin Fowler的Circuit Breaker一文裤唠。“斷路器”本身是一種開關(guān)裝置莹痢,用于在電路上保護線路過載种蘸,當(dāng)線路中有電器發(fā)生短路時墓赴,“斷路器”能夠及時的切斷故障電路,防止發(fā)生過載劈彪、發(fā)熱竣蹦、甚至起火等嚴(yán)重后果顶猜。

在分布式架構(gòu)中沧奴,斷路器模式的作用也是類似的,當(dāng)某個服務(wù)單元發(fā)生故障(類似用電器發(fā)生短路)之后长窄,通過斷路器的故障監(jiān)控(類似熔斷保險絲)滔吠,向調(diào)用方返回一個錯誤響應(yīng),而不是長時間的等待挠日。這樣就不會使得線程因調(diào)用故障服務(wù)被長時間占用不釋放疮绷,避免了故障在分布式系統(tǒng)中的蔓延。

Netflix Hystrix

在Spring Cloud中使用了Hystrix 來實現(xiàn)斷路器的功能嚣潜。Hystrix是Netflix開源的微服務(wù)框架套件之一冬骚,該框架目標(biāo)在于通過控制那些訪問遠程系統(tǒng)、服務(wù)和第三方庫的節(jié)點懂算,從而對延遲和故障提供更強大的容錯能力只冻。Hystrix具備擁有回退機制和斷路器功能的線程和信號隔離,請求緩存和請求打包计技,以及監(jiān)控和配置等功能喜德。

下面我們來看看如何使用Hystrix。

準(zhǔn)備工作

在開始加入斷路器之前垮媒,我們先拿之前構(gòu)建兩個微服務(wù)為基礎(chǔ)進行下面的操作舍悯,主要使用下面幾個工程:

  • chapter9-1-1
    • eureka-server工程:服務(wù)注冊中心,端口1111
    • compute-service工程:服務(wù)單元睡雇,端口2222
  • chapter9-1-2
    • eureka-ribbon:通過ribbon實現(xiàn)的服務(wù)單元萌衬,依賴compute-service的服務(wù),端口3333
    • eureka-feign:通過feign實現(xiàn)的服務(wù)單元它抱,依賴compute-service的服務(wù)奄薇,端口3333

Ribbon中引入Hystrix

  • 依次啟動eureka-server、compute-service抗愁、eureka-ribbon工程
  • 訪問http://localhost:1111/可以看到注冊中心的狀態(tài)
  • 訪問http://localhost:3333/add馁蒂,調(diào)用eureka-ribbon的服務(wù),該服務(wù)會去調(diào)用compute-service的服務(wù)蜘腌,計算出10+20的值沫屡,頁面顯示30
  • 關(guān)閉compute-service服務(wù),訪問http://localhost:3333/add撮珠,我們獲得了下面的報錯信息
Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat Jun 25 21:16:59 CST 2016
There was an unexpected error (type=Internal Server Error, status=500).
I/O error on GET request for "http://COMPUTE-SERVICE/add?a=10&b=20": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect

為了避免出現(xiàn)上面的錯誤沮脖,我們來引入斷路器

快速入門

  • pom.xml中引入依賴hystrix依賴
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
  • 在eureka-ribbon的主類RibbonApplication中使用@EnableCircuitBreaker注解開啟斷路器功能:
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public class RibbonApplication {

    @Bean
    @LoadBalanced
    RestTemplate restTemplate() {
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(RibbonApplication.class, args);
    }

}

或者金矛,我們可以這樣寫:

@SpringCloudApplication
public class ConsumerApplication {

    @Bean
    //負(fù)載均衡
    @LoadBalanced
    RestTemplate restTemplate(){
        return new RestTemplate();
    }

    public static void main(String[] args) {
        SpringApplication.run(ConsumerApplication.class,args);
    }
}

因為一個@SpringCloudApplication注解就包含了上面三種注解


package org.springframework.cloud.client;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootApplication
@EnableDiscoveryClient
@EnableCircuitBreaker
public @interface SpringCloudApplication {
}
  • 改造原來的服務(wù)消費方式,新增ComputeService類勺届,在使用ribbon消費服務(wù)的函數(shù)上增加@HystrixCommand注解來指定回調(diào)方法驶俊。
@Service
public class ComputeService {

    @Autowired
    RestTemplate restTemplate;

    @HystrixCommand(fallbackMethod = "addServiceFallback")
    public String addService() {
        return restTemplate.getForEntity("http://COMPUTE-SERVICE/add?a=10&b=20", String.class).getBody();
    }

    public String addServiceFallback() {
        return "error";
    }

}
  • 提供rest接口的Controller改為調(diào)用ComputeService的addService
@RestController
public class ConsumerController {

    @Autowired
    private ComputeService computeService;

    @RequestMapping(value = "/add", method = RequestMethod.GET)
    public String add() {
        return computeService.addService();
    }

}

更多關(guān)于Hystrix的使用可參考How To Use

Feign使用Hystrix

注意這里說的是“使用”胚膊,沒有錯故俐,我們不需要在Feigh工程中引入Hystix,F(xiàn)eign中已經(jīng)依賴了Hystrix紊婉,我們可以在未做任何改造前药版,嘗試下面你的操作:

  • 依次啟動eureka-server、compute-service喻犁、eureka-feign工程
  • 訪問http://localhost:1111/可以看到注冊中心的狀態(tài)
  • 訪問http://localhost:3333/add槽片,調(diào)用eureka-feign的服務(wù),該服務(wù)會去調(diào)用compute-service的服務(wù)肢础,計算出10+20的值还栓,頁面顯示30
  • 關(guān)閉compute-service服務(wù),訪問http://localhost:3333/add乔妈,我們獲得了下面的報錯信息
Whitelabel Error Page

This application has no explicit mapping for /error, so you are seeing this as a fallback.

Sat Jun 25 22:10:05 CST 2016
There was an unexpected error (type=Internal Server Error, status=500).
add timed-out and no fallback available.

如果您夠仔細(xì)蝙云,會發(fā)現(xiàn)與在ribbon中的報錯是不同的,看到add timed-out and no fallback available這句路召,或許您已經(jīng)猜到什么勃刨,看看我們的控制臺,可以看到報錯信息來自hystrix-core-1.5.2.jar股淡,所以在這個工程中身隐,我們要學(xué)習(xí)的就是如何使用Feign中集成的Hystrix。

  • 使用@FeignClient注解中的fallback屬性指定回調(diào)類
@FeignClient(value = "compute-service", fallback = ComputeClientHystrix.class)
public interface ComputeClient {

    @RequestMapping(method = RequestMethod.GET, value = "/add")
    Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b);

}
  • 創(chuàng)建回調(diào)類ComputeClientHystrix唯灵,實現(xiàn)@FeignClient的接口贾铝,此時實現(xiàn)的方法就是對應(yīng)@FeignClient接口中映射的fallback函數(shù)。
@Component
public class ComputeClientHystrix implements ComputeClient {

    @Override
    public Integer add(@RequestParam(value = "a") Integer a, @RequestParam(value = "b") Integer b) {
        return -9999;
    }

}
  • 再用之前的方法驗證一下埠帕,是否在compute-service服務(wù)不可用的情況下垢揩,頁面返回了-9999。

關(guān)于Feign的更多使用方法可參考:Feign

完整示例:Chapter9-1-3

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末敛瓷,一起剝皮案震驚了整個濱河市叁巨,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌呐籽,老刑警劉巖锋勺,帶你破解...
    沈念sama閱讀 212,884評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件蚀瘸,死亡現(xiàn)場離奇詭異,居然都是意外死亡庶橱,警方通過查閱死者的電腦和手機贮勃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,755評論 3 385
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來苏章,“玉大人寂嘉,你說我怎么就攤上這事〔冀” “怎么了垫释?”我有些...
    開封第一講書人閱讀 158,369評論 0 348
  • 文/不壞的土叔 我叫張陵丝格,是天一觀的道長撑瞧。 經(jīng)常有香客問我,道長显蝌,這世上最難降的妖魔是什么预伺? 我笑而不...
    開封第一講書人閱讀 56,799評論 1 285
  • 正文 為了忘掉前任,我火速辦了婚禮曼尊,結(jié)果婚禮上酬诀,老公的妹妹穿的比我還像新娘。我一直安慰自己骆撇,他們只是感情好瞒御,可當(dāng)我...
    茶點故事閱讀 65,910評論 6 386
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著神郊,像睡著了一般肴裙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涌乳,一...
    開封第一講書人閱讀 50,096評論 1 291
  • 那天蜻懦,我揣著相機與錄音,去河邊找鬼夕晓。 笑死宛乃,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的蒸辆。 我是一名探鬼主播征炼,決...
    沈念sama閱讀 39,159評論 3 411
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼躬贡!你這毒婦竟也來了谆奥?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,917評論 0 268
  • 序言:老撾萬榮一對情侶失蹤逗宜,失蹤者是張志新(化名)和其女友劉穎空骚,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體擂仍,經(jīng)...
    沈念sama閱讀 44,360評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,673評論 2 327
  • 正文 我和宋清朗相戀三年肋坚,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片肃廓。...
    茶點故事閱讀 38,814評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖盲赊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情哀蘑,我是刑警寧澤,帶...
    沈念sama閱讀 34,509評論 4 334
  • 正文 年R本政府宣布绘迁,位于F島的核電站合溺,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏缀台。R本人自食惡果不足惜棠赛,卻給世界環(huán)境...
    茶點故事閱讀 40,156評論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望膛腐。 院中可真熱鬧睛约,春花似錦、人聲如沸依疼。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,882評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽律罢。三九已至膀值,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間误辑,已是汗流浹背沧踏。 一陣腳步聲響...
    開封第一講書人閱讀 32,123評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留巾钉,地道東北人翘狱。 一個月前我還...
    沈念sama閱讀 46,641評論 2 362
  • 正文 我出身青樓,卻偏偏與公主長得像砰苍,于是被迫代替她去往敵國和親潦匈。 傳聞我的和親對象是個殘疾皇子阱高,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,728評論 2 351

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