springcloud之Hystrix服務(wù)降級(jí)

Springcloud之Hystrix服務(wù)降級(jí)

服務(wù)雪崩

多個(gè)微服務(wù)之間調(diào)用時(shí)微酬,如果鏈路上某個(gè)微服務(wù)A的調(diào)用響應(yīng)時(shí)間過(guò)長(zhǎng)或者不可用,調(diào)用方就會(huì)占用越來(lái)越多的系統(tǒng)資源厅缺,進(jìn)而引起服務(wù)雪崩重抖。

對(duì)高流量的應(yīng)用,比失敗更糟糕的是踪古,應(yīng)用程序還可能導(dǎo)致服務(wù)之間的延遲增加含长,備份隊(duì)列,線(xiàn)程和其他資源緊張伏穆,導(dǎo)致整個(gè)系統(tǒng)發(fā)生更多的級(jí)聯(lián)故障拘泞。因此,需要對(duì)故障和延遲進(jìn)行隔離和管理枕扫,以便單個(gè)依賴(lài)關(guān)系失敗陪腌,不會(huì)影響整個(gè)服務(wù)。

是什么

用于服務(wù)降級(jí)(fallback),服務(wù)熔斷(break)诗鸭,服務(wù)限流(flowlimit)染簇,服務(wù)隔離,還有一個(gè)近實(shí)時(shí)的監(jiān)控强岸。

hystrix既可以隔離依賴(lài)服務(wù)的調(diào)用锻弓,還提供了準(zhǔn)實(shí)時(shí)的調(diào)用監(jiān)控(Hystrix Dashboard),Hystrix會(huì)持續(xù)地記錄所有通過(guò)Hystrix發(fā)起的請(qǐng)求的執(zhí)行信息请唱,并圖表展示弥咪,包括每秒執(zhí)行了多少請(qǐng)求,多少成功十绑,多少失敗等聚至。

服務(wù)降級(jí)

服務(wù)降級(jí)即兜底方法fallback,有以下幾種途徑會(huì)產(chǎn)生服務(wù)降級(jí)本橙,即超時(shí)扳躬,異常,服務(wù)宕機(jī)甚亭,線(xiàn)程池或信號(hào)量打滿(mǎn)等贷币。

服務(wù)端配置

啟動(dòng)類(lèi)增加@EnableCircuitBreaker注解

@SpringBootApplication
@EnableEurekaClient
@EnableCircuitBreaker
public class CloudProviderHystrixPayment8001 {
    public static void main(String[] args) {
        SpringApplication.run(CloudProviderHystrixPayment8001.class, args);
    }
}

通過(guò)@HystrixCommand注解,指明fallbackMethod方法和超時(shí)時(shí)間限制亏狰。超過(guò)時(shí)間后役纹,則調(diào)用fallbackMethod指定的方法,fallbackMethod必須與被注解的函數(shù)具有相同的函數(shù)簽名暇唾。

    @HystrixCommand(fallbackMethod = "paymentInfo_timeoutHandler", commandProperties = {
            @HystrixProperty(name = "execution.isolation.thread.timeoutInMilliseconds", value = "5000") })
    public String paymentInfoTimeout(Integer id) {
        log.info("{}", Thread.currentThread().getName()+" running ...");
        Integer timeout = 3;
        try {
            TimeUnit.SECONDS.sleep(timeout);
        } catch (InterruptedException e) {
//          e.printStackTrace();
        }
        
        log.info("{}", " run over...");
        
        return "線(xiàn)程池: " + Thread.currentThread().getName() + " paymentInfo_timeout, id:" + id;
    }

    public String paymentInfo_timeoutHandler(Integer id) {
        log.info("hystrix超時(shí)處理...");
        return "線(xiàn)程池: " + Thread.currentThread().getName() + " System busy, id:" + id;
    }

客戶(hù)端配置

客戶(hù)端啟動(dòng)類(lèi)配置@EnableHystrix

@SpringBootApplication
@EnableFeignClients
@EnableHystrix
public class CloudConsumerFeignHystrixOrder80 {
    public static void main(String[] args) {
        SpringApplication.run(CloudConsumerFeignHystrixOrder80.class, args);
    }
}

配置文件開(kāi)啟hystrix支持


```feign:
  client:
    config:
      default:
        connect-timeout: 5000
        read-timeout: 5000
        logger-level: full
  compression:
    request:
      enabled: false
    response:
      enabled: false
  hystrix:
    enabled: true

客戶(hù)端配置促脉,單獨(dú)在函數(shù)上配置fallback,并指定超時(shí)時(shí)間

@RestController
@RequestMapping(value="/consumer")
@Slf4j
public class OrderFeignHystrixController {
    @Autowired
    private PaymentFeignHystrixService paymentFeignService;

    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfoOk(@PathVariable("id") Integer id) {
        String result = paymentFeignService.paymentInfoOk(id);
        log.info("******result:"+result);
        return result;
    }

    @GetMapping("/payment/hystrix/timeout/{id}")
    @HystrixCommand(fallbackMethod = "paymentTimeoutFallbackMethod", commandProperties = {
            @HystrixProperty(name="execution.isolation.thread.timeoutInMilliseconds", value="1500")
    })
    public String paymentInfoTimeout(@PathVariable("id") Integer id) {
        String result = paymentFeignService.paymentInfoTimeout(id);
        log.info("*******result:"+result);
        return result;
    }
        
    public String paymentTimeoutFallbackMethod(@PathVariable("id") Integer id) {
        return "等不及了, 快上車(chē)";
    }
}

客戶(hù)端配置策州,全局fallback瘸味。通過(guò)@DefaultProperties注解的defaultFallback屬性

@RestController
@RequestMapping(value="/consumer")
@Slf4j
@DefaultProperties(defaultFallback="payment_global_fallbackmethod")
public class OrderFeignHystrixController {
    @Autowired
    private PaymentFeignHystrixService paymentFeignService;

    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfoOk(@PathVariable("id") Integer id) {
        String result = paymentFeignService.paymentInfoOk(id);
        log.info("******result:"+result);
        return result;
    }

    @GetMapping("/payment/hystrix/timeout/{id}")
    @HystrixCommand
    public String paymentInfoTimeout(@PathVariable("id") Integer id) {
        String result = paymentFeignService.paymentInfoTimeout(id);
        log.info("*******result:"+result);
        return result;
    }
    
    public String payment_global_fallbackmethod() {
        log.info("global fallback method...");
        return "global異常處理信息,請(qǐng)稍后再試...";
    }
}

上述方式還不夠極簡(jiǎn)够挂,比如fallback函數(shù)與函數(shù)耦合在一起旁仿,可以進(jìn)一步解耦。通過(guò)實(shí)現(xiàn)@FeignClient的接口孽糖,指明fallback類(lèi)枯冈。其中每個(gè)函數(shù)對(duì)應(yīng)的就是fallback函數(shù)。

@Service
public class PaymentFeginHystrixFallbackService implements PaymentFeignHystrixService {
    @Override
    public String paymentInfoOk(Integer id) {
        return "fall back, ok...";
    }

    @Override
    public String paymentInfoTimeout(Integer id) {
        return "fall back, timeout...";
    }
}

@FeignClient的接口上办悟,指明fallback類(lèi)尘奏。這樣便可實(shí)現(xiàn),fallback函數(shù)與函數(shù)的進(jìn)一步解耦誉尖。

@Service
@FeignClient(value="cloud-payment-hystrix-service", fallback=PaymentFeginHystrixFallbackService.class)
public interface PaymentFeignHystrixService {
    @GetMapping("/payment/hystrix/ok/{id}")
    public String paymentInfoOk(@PathVariable("id") Integer id);

    @GetMapping("/payment/hystrix/timeout/{id}")
    public String paymentInfoTimeout(@PathVariable("id") Integer id);
}

服務(wù)熔斷

類(lèi)比保險(xiǎn)絲罪既,分為三個(gè)步驟:服務(wù)降級(jí)->進(jìn)而熔斷->恢復(fù)調(diào)用鏈路。

熔斷機(jī)制是應(yīng)對(duì)雪崩效應(yīng)的一種微服務(wù)鏈路保護(hù)機(jī)制。當(dāng)扇出鏈路的某個(gè)微服務(wù)出錯(cuò)不可用或者響應(yīng)時(shí)間太長(zhǎng)時(shí)琢感,會(huì)進(jìn)行服務(wù)的降級(jí)丢间,進(jìn)而熔斷該節(jié)點(diǎn)微服務(wù)的調(diào)用,快速返回錯(cuò)誤的響應(yīng)信息驹针。當(dāng)檢測(cè)到該節(jié)點(diǎn)微服務(wù)調(diào)用響應(yīng)正常后烘挫,恢復(fù)調(diào)用鏈路。

SpringCloud中柬甥,熔斷機(jī)制是通過(guò)Hystrix實(shí)現(xiàn)饮六。Hystrix會(huì)監(jiān)控微服務(wù)間的調(diào)用情況,當(dāng)失敗的調(diào)用到一定閾值苛蒲,默認(rèn)是5s內(nèi)20次調(diào)用失敗卤橄,就會(huì)啟動(dòng)熔斷機(jī)制。熔斷機(jī)制的注解是通過(guò)@HystrixCommand實(shí)現(xiàn)的臂外。

熔斷類(lèi)型:

  • 熔斷打開(kāi):請(qǐng)求不在進(jìn)行調(diào)用當(dāng)前服務(wù)窟扑,內(nèi)部設(shè)置時(shí)鐘一般為MTTR(平均故障處理時(shí)間),當(dāng)打開(kāi)時(shí)長(zhǎng)達(dá)到所設(shè)時(shí)鐘則進(jìn)入半熔斷狀態(tài)漏健。
  • 熔斷關(guān)閉:正常情況嚎货。
  • 熔斷半開(kāi):部分請(qǐng)求根據(jù)規(guī)則調(diào)用當(dāng)前服務(wù),如果請(qǐng)求成功且符合規(guī)則則認(rèn)為當(dāng)前服務(wù)恢復(fù)正常蔫浆,關(guān)閉熔斷殖属。

涉及斷路器的三個(gè)重要參數(shù):快照時(shí)間窗,請(qǐng)求總數(shù)閾值瓦盛,錯(cuò)誤百分比閾值洗显。

  • 快照時(shí)間窗:斷路器確定是否打開(kāi)需要統(tǒng)計(jì)一些請(qǐng)求和錯(cuò)誤數(shù)據(jù),統(tǒng)計(jì)的時(shí)間范圍就是快照時(shí)間窗谭溉,默認(rèn)是10s墙懂。
  • 請(qǐng)求總數(shù)閾值:在快照時(shí)間窗內(nèi)橡卤,必須滿(mǎn)足請(qǐng)求總數(shù)閾值才有資格熔斷扮念。默認(rèn)是20,意味著10s內(nèi)碧库,如果Hystrix命令的調(diào)用次數(shù)不足20次柜与,即使所有的請(qǐng)求都超時(shí)或其他原因,斷路器都不會(huì)打開(kāi)嵌灰。
  • 錯(cuò)誤百分比閾值:當(dāng)請(qǐng)求總數(shù)在快照時(shí)間窗內(nèi)超過(guò)了閾值弄匕,比如發(fā)生了30次調(diào)用,如果再30次調(diào)用中沽瞭,有16次發(fā)送了超時(shí)異常迁匠,則超過(guò)了50%的錯(cuò)誤百分比,在默認(rèn)設(shè)定50%閾值的情況下,這時(shí)候會(huì)將斷路器打開(kāi)城丧。

原來(lái)的主邏輯要如何恢復(fù)延曙?

當(dāng)開(kāi)啟的時(shí)候,所有請(qǐng)求都不會(huì)進(jìn)行轉(zhuǎn)發(fā)亡哄;一段時(shí)間之后(默認(rèn)是5s)枝缔,這個(gè)時(shí)候斷路器是半開(kāi)狀態(tài),會(huì)讓其中一個(gè)請(qǐng)求進(jìn)行轉(zhuǎn)發(fā)蚊惯,如果成功愿卸,斷路器會(huì)關(guān)閉,若失敗截型,繼續(xù)開(kāi)啟趴荸。重復(fù)上述步驟。

以下配置宦焦,即為服務(wù)熔斷

@HystrixCommand(fallbackMethod="paymentCircuitBreakerFallback", commandProperties = {
            @HystrixProperty(name="circuitBreaker.enabled", value="true"),//是否開(kāi)啟斷路器 
            @HystrixProperty(name="circuitBreaker.requestVolumeThreshold", value="10"),//請(qǐng)求次數(shù)
            @HystrixProperty(name="circuitBreaker.sleepWindowInMilliseconds", value="10000"),//時(shí)間窗口期
            @HystrixProperty(name="circuitBreaker.errorThresholdPercentage", value="60")//失敗率達(dá)到多少后跳閘
    })
    public String paymentCircuitBreaker(@PathVariable("id") Integer id){
        if(id<0) {
            throw new RuntimeException("id不能為負(fù)數(shù)");
        }
        String serialNumber = IdUtil.simpleUUID();
        return Thread.currentThread().getName()+"\t"+" ok, no: "+serialNumber;
    }
    
    public String paymentCircuitBreakerFallback(@PathVariable("id") Integer id) {
        return "id 不能為負(fù)赊舶,請(qǐng)重試..., id: "+id;
    }
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市赶诊,隨后出現(xiàn)的幾起案子笼平,更是在濱河造成了極大的恐慌,老刑警劉巖舔痪,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件寓调,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡锄码,警方通過(guò)查閱死者的電腦和手機(jī)夺英,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)滋捶,“玉大人痛悯,你說(shuō)我怎么就攤上這事≈乜撸” “怎么了载萌?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)巡扇。 經(jīng)常有香客問(wèn)我扭仁,道長(zhǎng),這世上最難降的妖魔是什么厅翔? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任乖坠,我火速辦了婚禮,結(jié)果婚禮上刀闷,老公的妹妹穿的比我還像新娘熊泵。我一直安慰自己仰迁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布顽分。 她就那樣靜靜地躺著轩勘,像睡著了一般。 火紅的嫁衣襯著肌膚如雪怯邪。 梳的紋絲不亂的頭發(fā)上绊寻,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音悬秉,去河邊找鬼澄步。 笑死,一個(gè)胖子當(dāng)著我的面吹牛和泌,可吹牛的內(nèi)容都是我干的村缸。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼武氓,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼梯皿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起县恕,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤东羹,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后忠烛,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體属提,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年美尸,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了冤议。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡师坎,死狀恐怖恕酸,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情胯陋,我是刑警寧澤蕊温,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站惶岭,受9級(jí)特大地震影響寿弱,放射性物質(zhì)發(fā)生泄漏犯眠。R本人自食惡果不足惜按灶,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望筐咧。 院中可真熱鬧鸯旁,春花似錦噪矛、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至韭赘,卻和暖如春缩滨,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背泉瞻。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工脉漏, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人袖牙。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓侧巨,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親鞭达。 傳聞我的和親對(duì)象是個(gè)殘疾皇子司忱,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350