Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

在Spring Cloud微服務體系中,因爲限流熔斷組件Hystrix開源版本不在維護,所以國內很多有相似需求的公司已經將眼光轉向阿里開源的Sentinel框架。而如下要介紹的正是做者最近兩個月的真實項目實踐過程,這中間被很多網絡Demo示例級別水文誤導過,爲了以正視聽特將實踐過程加以總結,但願可以幫到有相似須要的朋友!git

1、Sentinel概述

在基於Spring Cloud構建的微服務體系中,服務之間的調用鏈路會隨着系統的演進變得愈來愈長,這無疑會增長了整個系統的不可靠因素。在併發流量比較高的狀況下,因爲網絡調用之間存在必定的超時時間,鏈路中的某個服務出現宕機都會大大增長整個調用鏈路的響應時間,而瞬間的流量洪峯則會致使這條鏈路上全部服務的可用線程資源被打滿,從而形成總體服務的不可用,這也就是咱們常說的「雪崩效應」。github

而在微服務系統設計的過程當中,爲了應對這樣的糟糕狀況,最經常使用的手段就是進行」流量控制「以及對網絡服務的調用實現「熔斷降級」。所謂流量控制就是根據服務的承載能力指定一個策略,對必定時間窗口內的網絡調用次數進行限制,例如1s內某個服務最多隻能處理10個請求,那麼1s內的第11+的請求會被被限制丟棄;而熔斷降級的概念則是說在A服務→B服務調用過程當中,按照必定的規則A服務發現調用B服務常常失敗或響應時間過長,若是觸發了A服務對B服務調用的熔斷降級規則,那麼在必定時間窗口內,A服務在處理請求的過程當中對於B服務的調用將會直接在A服務的邏輯中被熔斷降級,請求則不會經過網絡打到B服務,從而避免A服務因爲過長的超時時間致使自身資源被耗盡的狀況發生。spring

雖然咱們知道以上兩種手段很是有用,但若沒有合適的技術來支持,就好像一句話說的「雖然明白不少道理,可是依然過很差這一輩子」同樣。而Sentinel就是這樣一種技術,它是阿里巴巴開源的一款客戶端限流組件,能夠與Spring Cloud微服務體系無縫地集成;而與之對應的是另一款Netflix公司推出的知名度也比較高的Hystrix組件,Hystrix也是Spring Cloud官方集成熔斷限流組件,只不過相對於Sentinel來講,Hystrix所提供的功能和靈活度比較低,而且它目前已經處於開源版本暫停維護的狀態,所以目前國內不少基於Spring Cloud搞微服務的公司都轉向了Sentinel。關於兩者的對比因爲不是本文的重點,這裏就再也不贅述,你們搜索下就好(ps:可能網上也沒幾篇能說明白的文章,關鍵還在於你們實際使用對比)。編程

2、Sentinel+Apollo架構說明

Sentinel開源版本架構json

在Github Sentinel官方Wiki說明以及網上一大堆的水文中,關於Sentinel的資料已經不少了,可是大多數屬於Demo級別,因此本文不想過多的耗費你們的精力(由於在學習過程當中,做者也被誤導過)。如下將從實際生產的使用方式上來闡述如何構建Sentinel的使用架構。bootstrap

從本質上說Sentinel與Hystrix是一類性質的熔斷限流組件,之因此說它們只是組件就在於它們都須要內嵌於微服務應用自己的主進程之中,全部的限流、熔斷策略及指標信息的收集等邏輯都是基於客戶端的(這裏不要對客戶端有所誤會,它指的是處於調用端上游的微服務自己)。而這一點是明顯區別於Service Mesh(服務網格)架構中將熔斷、限流等邏輯抽象在SideCar(邊車)而不是微服務應用自己的。api

所以從這種意義上說,Sentinel的使用應該是並不複雜的,它應該與Hystrix同樣,在Spring Cloud微服務應用中引入相關依賴便可。事實上從某種程度來講的確如此,只不過Sentinel提供了比Hystrix要強一點的規則配置能力,提供了能夠進行限流、熔斷降級以及熱點、受權等其餘規則統一配置和管理的控制檯服務->sentinel-dashboard。緩存

雖然如此,但這也並無改變Sentinel做爲客戶端限流組件性質,經過控制檯配置的規則依然要推送到微服務應用Sentinel客戶端自己才能生效,而微服務之間的調用鏈路等指標信息也須要推送給Sentinel控制檯,才能比較方便地使用Sentinel提供的一些能力,所以在開源的架構版本中須要微服務應用自己開啓獨立端口與sentinel-dashboard進行通訊,從而獲取配置規則以及上送微服務應用各種指標信息。而這一點,顯然也會佔用微服務額外的資源,而且因爲sentinel-dashboard在此條件下並不具有集羣部署能力,所以也會造成一個單節點問題,可是有一套控制檯總好過於沒有,若是但願比較方便快速地應用Sentinel這也是一種代價。此時的Sentinel架構以下圖所示:網絡

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

在開源版本架構中,經過sentinel-dashboard控制檯配置的限流、熔斷降級等規則都是存儲於Sentinel控制檯服務內存之中的,若是控制檯服務重啓或者微服務應用重啓都會致使規則丟失。而這在生產環境下是不可接受的,所以Sentinel在官方的生產架構指導中也是推薦使用第三方數據源(如本文的Apollo)做爲永久存儲中心,這樣各個微服務的限流、降級規則均可以永久存儲。雖然Sentinel官方推薦使用第三方數據源做爲規則存儲中心,目前也提供了針對Apollo、Nacos、Zookeeper、Redis、Consul、Spring Cloud Config等多種存儲源的依賴集成Jar,可是卻並無針對這些數據源提供一個能夠實際使用的sentinel-dashboard第三方數據源存儲版本,因此當你選擇了一種數據源那麼就須要你本身對sentinel-dashboard項目進行改造,這裏做者針對Sentinel 1.7.0(成文時最新版本)使用Apollo數據源改造了一個版本,全部規則基本可用,但可能會有細節的Bug須要自行Fix。具體代碼改造點見Github連接:架構

https://github.com/manongwudi/Sentinel/commit/f3a27adb6fdbf13d9eaa4510e317c1b55c206e89

關於以上sentinel-dashboard接入Apollo數據源的代碼改造狀況,你們能夠詳細參考上述連接,這裏做者只說如下幾個重點:

目前官方推薦的方式是經過Apollo的開放平臺受權的方式進行寫入,所以咱們須要在sentinel-dashboard項目pom.xml文件引入如下依賴:

<!-- Apollo配置依賴 -->
<dependency>
    <groupId>com.ctrip.framework.apollo</groupId>
    <artifactId>apollo-openapi</artifactId>
    <version>1.5.0</version>
</dependency>

以後咱們須要在Apollo Portal建立一個針對sentinel-dashboard的應用,具體建立方法以下圖所示:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

以上咱們建立了一個針對Sentinel控制檯的應用(這裏的應用是Apollo配置中心的基本概念,具體微服務接入Apollo的方法,你們能夠自行搜索)。

建立應用後,將來Sentinel控制檯在啓動是須要指定Apollo應用ID才能接入Apollo,而接入Apollo以後Sentinel的規則須要寫入該應用下的namespace空間,所以還須要建立針對該應用的namespace空間,具體建立方式以下圖所示:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

點擊進入應用,而後點擊「添加Namespace",建立一個具體存儲Sentinel各類限流、熔斷降級等規則的Apollo存儲空間,這裏須要注意的是所建立的空間類型必定要是"public"公共空間,由於最終這些規則是須要具體的微服務應用去獲取的,而在Apollo中應用下只有公共Namecspace才能被其餘應用繼承。

最後咱們在Apollo控制檯選擇「管理員工具->開放平臺受權管理」建立基於該應用的開放受權信息。

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

此時生成的Token信息將做爲sentinel-dashboardApollo接口對接的重要憑證被配置。經過上述幾個步驟,咱們基本上就完成了sentinel-dashboard對接Apollo的準備工做,剩下的就是針對sentinel-dashboard的具體代碼改造,可參考前面的Github連接。改造中可以抽離的配置以下:

#Apollo本地演示環境
#Apollo應用ID
apollo.app.id=sentinel
#Apollo應用下對應的具體集羣標識
apollo.cluster.name=local
#Apollo存儲空間名稱
apollo.namespace.name=sentinel-rule
#Apollo控制檯地址
apollo.portal.url=http://127.0.0.1:8070
#Apollo控制檯用戶名
apollo.modify.user=apollo
apollo.release.user=apollo
#Apollo開放平臺憑證
apollo.application.token=2647efacc9d55445f4055247cd028af60dd604b6

以上配置在編寫具體的鏈接代碼時會使用到,詳情請參考具體改造代碼!

爲何要使用Apollo?Apollo是一款攜程開源的配置中心,在目前基於Spring Cloud的微服務體系中也有一款官方的配置中心Spring Cloud Config。從實際的使用狀況看,目前Apollo比起Spring Cloud Config從功能上說要更全一些,若是你的公司在使用Spring Cloud Config司目前使用的是Apollo做爲配置中心,所以選擇的是Apollo做爲Sentinel第三方存儲數據源(須要注意Apollo的版本,若是你所使用的Apollo版本比較老,可能會不兼容)。

引入Apollo做爲Sentinel數據存儲源後,此時的Sentinel架構以下圖所示:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

3、Spring Cloud微服務集成Sentinel

講到這裏,咱們還只是完成了Sentinel控制檯與Apollo數據存儲源之間的打通,那麼對於具體的Spring Cloud微服務應用而言,在代碼編程上該如何接入和使用Sentinel呢?

微服務鏈接Sentinel控制檯

在默認狀況下微服務應用能夠直接鏈接Sentinel控制檯,從而經過Sentinel控制檯獲取限流、熔斷降級等規則信息。具體步驟以下:

首先咱們須要在項目pom.xml文件中引入Sentinel相關依賴Jar,代碼以下:

<!--Sentinel熔斷限流組件依賴-->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.1.1.RELEASE</version>
    <!--根據實際狀況決定是否排除衝突依賴-->
    <exclusions>
        <exclusion>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
        </exclusion>
    </exclusions>
</dependency>

以後咱們須要在項目的配置文件中加入Spring Cloud微服務鏈接sentinel dashboard的配置(此時微服務還還沒有引入Apollo配置中心,引入Apollo配置中心後也能夠加在配置中心),以下:

#sentinel
#在微服務應用中開啓鏈接sentinel-dashboard的鏈接端口
spring.cloud.sentinel.transport.port = 8719
#sentinel-dashboard控制檯地址
spring.cloud.sentinel.transport.dashboard = http://127.0.0.1:9090

在不考慮第三方數據源永久存儲的狀況下,以上方式也能夠直接使用Sentinel對微服務進行限流、熔斷降級等邏輯,只不過這些規則並不能永久存儲!

微服務鏈接Apollo配置中心

接下來咱們將Spring Cloud微服務接入Apollo配置中心,並經過Apollo配置中心獲取從Sentinel控制檯持久化到Apollo應用存儲空間的Sentinel規則。

引入Sentinel規則Apollo數據源依賴,該依賴也會默認包含Apollo自己的客戶端依賴,所以也不用在額外引入其餘JAR,代碼以下:

<!--Sentinel規則Apollo數據源依賴-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-apollo</artifactId>
    <version>1.7.0</version>
    <!--根據實際狀況決定是否排除衝突依賴-->
    <exclusions>
        <exclusion>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-extension</artifactId>
        </exclusion>
        <exclusion>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>

接下來配置Spring Cloud微服務鏈接Apollo配置中心的基本信息,以下:

#Apollo中建立的微服務應用ID
app.id = pay-notify
#打開Apollo接入開關
apollo.bootstrap.enabled = true
apollo.bootstrap.eagerLoad.enabled = true

#apollo configserver地址不是portal
apollo.meta = http://127.0.0.1:8080
# 自定義本地配置文件緩存路徑
apollo.cacheDir = ./config
#指定apollo命名空間
apollo.namespace =application,db,logback
#指定apollo集羣
apollo.cluster=local

若是但願在Apollo中生效的配置可以及時被Spring Cloud微服務感知到,咱們還須要在微服務主類中加入@EnableApolloConfig註解,代碼以下:

@SpringBootApplication
@EnableFeignClients(basePackageClasses = {PayChannelFeignService.class})
@EnableDiscoveryClient
@EnableTransactionManagement
@EnableApolloConfig
public class PayNotifyApplication {

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

    // 註解支持的配置Bean
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }
}

此時拋開Sentinel自己不說,Spring Cloud微服務也能夠經過Apollo進行配置管理了!

那麼嵌入Spring Cloud微服務應用的Sentitle客戶端該如何獲取Apollo中關於Sentinel規則的配置呢?在文章前面關於Sentinel+Apollo架構的說明中,sentinel-dashboard是將規則寫入它在Apollo所在應用的公共空間下,所以其餘微服務自己是能夠經過Apollo繼承並讀取到這些配置的。只是咱們在進行sentinel-dashboard的改造將規則的寫入編成了必定的前/後綴標示,因此Spring Cloud微服務要想匹配到相應的規則,也須要在自身服務的配置中約定讀取方式,具體以限流、熔斷降級這兩個規則爲例進行配置,以下:

#指定該數據源爲限流規則
spring.cloud.sentinel.datasource.flow.apollo.rule-type = flow
spring.cloud.sentinel.datasource.degrade.apollo.rule-type = degrade

#指定該規則在apollo應用中的key,從而實現約定讀取
#spring.cloud.sentinel.datasource.ds1.apollo.flow-rules-key = ${spring.application.name}-${spring.cloud.sentinel.datasource.flow.apollo.rule-type}
spring.cloud.sentinel.datasource.flow.apollo.namespaceName = sentinel-rule
spring.cloud.sentinel.datasource.flow.apollo.flowRulesKey = ${spring.application.name}-${spring.cloud.sentinel.datasource.flow.apollo.rule-type}

#降級規則
spring.cloud.sentinel.datasource.degrade.apollo.namespaceName = sentinel-rule
spring.cloud.sentinel.datasource.degrade.apollo.flowRulesKey = ${spring.application.name}-${spring.cloud.sentinel.datasource.degrade.apollo.rule-type}

經過上述配置能夠看出,咱們是經過Sentinel客戶端依賴約定的配置方式,對各種規則經過命名規則進行了匹配(這裏Sentinel規則的命名規則能夠結合實際的管理需求進行約定,確保sentinel-dashboard寫入與微服務讀取匹配就行)!例如:若是從管理角度分類,能夠加上{部門名稱}.sentinel-rule,這要求建立namespace公共空間時帶上部門名前綴。

4、微服務使用Sentinel的編程方式

經過上面操做,咱們已經從配置及環境方面完成了Sentinel與Spring Cloud微服務的接入,接下來咱們以實際的服務間調用爲例演示如何在Spring Cloud微服務體系下,使用Sentinel進行限流、熔斷降級等操做!以做者以前作過的支付系統爲例,其中有兩個微服務存在以下調用關係:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

以上兩個服務的調用示例,是在支付系統中對支付訂單狀態進行實時檢查的邏輯,目的是防止在出現支付調用鏈路中斷,致使的支付掉單問題。pay-check服務會在支付請求發送到第三方後接受一條延遲消息,並在必定時間後經過對比支付流水狀態與第三方渠道支付狀態,如發現狀態不一致,會經過Spring Cloud微服務間的Feign調用方式觸發支付通知服務pay-notify,從而實現支付鏈路的補償。這裏pay-notify提供的服務接口爲「/internel/pay/checkNotify」,關於這個服務接口,這裏咱們要求pay-notify服務要對該資源進行限流,從而防止流量過大而致使正常的通知鏈路受影響;而對於pay-check服務則須要實現對pay-notify服務該接口資源的熔斷降級邏輯防止因爲故障或網絡緣由致使pay-notify服務沒法被正常調用,從而影響pay-check服務的穩定性。

Sentinel限流編程

須要明確的是,限流動做自己是服務提供方作出的,因此若是須要針對某個微服務的應用接口使用Sentinel進行限流處理,那麼咱們能夠在該服務的入口經過@SentinelResource註解進行Sentinel資源配置,以上述實例爲例,咱們對pay-notify微服務接口/internel/pay/checkNotify進行以下資源定義:

@SentinelResource(value = "/pay/checkNotify", blockHandlerClass = SentinelFallback.class, blockHandler = "fallbackHandlerForCheckNotify")
@RequestMapping(value = "/pay/checkNotify", method = RequestMethod.POST)
public boolean checkNotify(@RequestParam(value = "paymentId") String paymentId,
        @RequestParam(value = "tradeNo") String tradeNo, @RequestParam(value = "status") int status,
        @RequestParam(value = "platform") String platform, @RequestParam(value = "platformtag") String platformtag,
        @RequestParam(value = "tradeTime") String tradeTime,
        @RequestParam(value = "notifyOrignMsg") String notifyOrignMsg,
        @RequestParam(value = "tradeStatus") String tradeStatus) {
    PayCoreNotifyEntity payCoreNotifyEntity = PayCoreNotifyEntity.builder().paymentId(paymentId).tradeNo(tradeNo)
            .status(status).platform(platform).platformtag(platformtag).tradeTime(tradeTime)
            .orignPlaintext(notifyOrignMsg).tradeStatus(tradeStatus).build();
    boolean result = false;
    try {
        result = payCheckNotifyServiceImpl.payCheckCallBack(payCoreNotifyEntity);
    } catch (CheckNotifyMsgException e) {
        log.error(e.toString() + "_" + e.getMessage(), e);
        CounterUtil.counter(Arrays.asList(Tag.of("exceptionType", e.getMessage())), "payNotifyExceptionMonitor");
    }
    return result;
}

在針對該接口進行Sentinel資源的定義時,爲了服務端不直接拋出BlockException異常,咱們配置了異常處理類及異常處理方法。blockHandler函數會在原資源方法被限流系統保護時被調用,而在SentinelFallback類中,針對該資源方法也定義了相應的地處理方法fallbackHandlerForCheckNotify,代碼以下:

@Slf4j
public class SentinelFallback {

    public static boolean fallbackHandlerForCheckNotify(String paymentId,
            @RequestParam(value = "tradeNo") String tradeNo, @RequestParam(value = "status") int status,
            @RequestParam(value = "platform") String platform, @RequestParam(value = "platformtag") String platformtag,
            @RequestParam(value = "tradeTime") String tradeTime,
            @RequestParam(value = "notifyOrignMsg") String notifyOrignMsg,
            @RequestParam(value = "tradeStatus") String tradeStatus, BlockException e) {
        log.error("對不起,該請求限流了,{}", e.toString());
        return false;
    }

須要注意的是Block異常處理函數,參數最後多一個BlockException,其他參數則須要與原函數一致,不然限流規則觸發後將沒法正常進入該fallback方法,而是直接拋出異常,服務消費方則直接收到500錯誤,輸出上會顯得不是很友好!關於限流資源異常處理代碼編程方式,以上只是參考,你們能夠寫的更優雅,例如能夠參考Feign的fallback編程方式。

定義Sentinel資源後,此時若是須要針對該資源進行限流規則的配置,咱們可使用sentinel-dashboard進行配置,如圖所示:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

pay-notify微服務節點上,選擇流控規則,並按照前面定義的Sentinel資源名稱進行限流規則配置,這裏咱們爲了便於測試,限流規則配置的極端些,選擇QPS方式,並定義閥值爲0。此時因爲已經將sentinel-dashbordApollo配置中心打通,所以也能從Apollo中看到已經持久化存儲的限流規則,以下圖所示:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

此時若是針對該資源方法進行網絡調用就會被Sentinel規則限流掉,例如經過postman/internel/pay/checkNotify接口進行網絡調用,服務端代碼運行以下:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

能夠看到此時針對該方法的調用已經觸發限流規則,並在拋出BlockException異常後,進入了咱們前面經過@SentinelResource註解定義的blockHandler方法!

Sentinel熔斷降級編程

熔斷降級針對的是對其餘服務資源進行網絡調用時,爲了防止外部服務的不穩定拖垮自身,當該服務出現不穩定狀態(例如調用超時或者異常比例升高等狀況),對該資源的調用動做進行限制,從而讓請求快速失敗,避免出現級聯錯誤的狀況。而當資源被降級後,在接下來的降級時間窗口內,對該資源的服務調用都會自動熔斷,而不會真正進行網絡調用,而在Sentinel中則默認會拋出DegradeException異常。

從使用方向上看熔斷降級規則邏輯的發生,是發生在服務消費方,而不是服務提供方。以上述例子舉例,pay-notify服務除了針對自身接口進行限流外,pay-checkpay-notify服務的調用也能夠進行熔斷降級處理。這裏咱們將pay-check服務中對pay-notify服務接口的調用方法進行Sentinel資源定義,代碼以下:

@SentinelResource(value = "/pay/goCheckNotify", blockHandler = "testNotifyFallback")
public boolean testNotify(String paymentId, String tradeNo, int status, String platform, String platformtag,
        String tradeTime, String notifyOrignMsg, String tradeStatus) throws BlockException {
    return notifyClient
            .checkNotify(paymentId, tradeNo, status, platform, platformtag, tradeTime, notifyOrignMsg, tradeStatus);
}

//熔斷降級異常處理方法
public boolean testNotifyFallback(String paymentId, String tradeNo, int status, String platform, String platformtag,
        String tradeTime, String notifyOrignMsg, String tradeStatus, BlockException ex) {
    log.error("服務被降級了!");
    //todo 調用其餘降級服務
    return false;
}

以後咱們經過Sentinel控制檯在微服務節點pay-check中針對該資源配置降級規則,以下圖所示:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

這裏的意思是對該資源方法的調用按照平均響應時間進行熔斷降級,當1S內持續進入5個請求,對應時刻的資源平均響應時間(秒級)均超過閥值,這裏配置的是200ms,那麼在接下來的時間窗口內,這裏配置的是10s,對該資源的調用都會自動進行熔斷,默認拋出DegradeException。爲了演示效果,這裏咱們將pay-notify服務的接口響應時間故意sleep(600ms),代碼以下:

try {
    Thread.sleep(600);
} catch (InterruptedException e) {
    e.printStackTrace();
}

接下來咱們經過JMeter調用pay-check服務,而pay-check服務將以Spring Cloud微服務的調用方式經過Feign來調用pay-notify的服務,以下圖所示:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

這裏咱們設置的請求方式爲1s內發送7次請求調用,按照熔斷降級規則,因爲前5個請求的響應時間都將超過200ms的閥值,所以第六、7個請求將被直接熔斷而進入fallback方法。代碼運行效果以下:

Spring Cloud微服務Sentinel+Apollo限流、熔斷實戰

從演示效果看熔斷降級規則已經生效,Sentinel拋出了DegradeException異常!

Sentinel與Feign的集成關係

在實際的Spring Cloud微服務開發中,微服務之間的調用能夠經過Feign來實現,與Spring Cloud微服務官方集成的Hystrix框架同樣,在Feign中若是須要開啓Sentinel熔斷降級邏輯,須要在調用端(示例中爲pay-check服務)配置中進行以下配置:

feign.sentinel.enabled = true

而做爲Spring Cloud微服務調用端,在基於Feign對其餘微服務存在接口調用的話,通常狀況下咱們還須要編寫基於Feign的調用代碼,並指定其fallback邏輯,以本文示例爲例:

@FeignClient(value = "pay-notify", configuration = PayNotifyClientConfiguration.class, fallbackFactory = PayNotifyClientFallbackFactory.class)
public interface PayNotifyClient {
    /**
     * 支付狀態覈對發生掉單現象時,經過此接口完成補單回調操做
     */
    @RequestMapping(value = "/internal/pay/checkNotify", method = RequestMethod.POST)
    boolean checkNotify(@RequestParam(value = "paymentId") String paymentId,
            @RequestParam(value = "tradeNo") String tradeNo, @RequestParam(value = "status") int status,
            @RequestParam(value = "platform") String platform, @RequestParam(value = "platformtag") String platformtag,
            @RequestParam(value = "tradeTime") String tradeTime,
            @RequestParam(value = "notifyOrignMsg") String notifyOrignMsg,
            @RequestParam(value = "tradeStatus") String tradeStatus);

其所指定的Fallback邏輯代碼以下:

public class PayNotifyClientFallbackFactory implements FallbackFactory<PayNotifyClient> {

    @Override
    public PayNotifyClient create(Throwable throwable) {
        return new PayNotifyClient() {
            @Override
            public boolean checkNotify(String paymentId, String tradeNo, int status, String platform,
                    String platformtag, String tradeTime, String notifyOrignMsg, String tradeStatus) {
                log.info("enter flow limit/fallback logic");
                log.error(throwable.getMessage());
                return false;
            }
        };
    }
}

@Slf4j
@Configuration
public class PayNotifyClientConfiguration {

    @Bean
    PayNotifyClientFallbackFactory payNotifyClientFallbackFactory() {
        return new PayNotifyClientFallbackFactory();
    }
}

須要說明的是,在微服務調用時,若是發送調用超時等狀況會直接進入以上Feign所指定的fallback邏輯;而Sentinel熔斷降級規則被觸發時在某些場景下,例如在上述以平均響應時間爲例的降級規則中,則只會直接進入@SentinelResource所指定的fallback方法,這一點也是Sentinel與Feign整合不夠優雅的地方,所以在編寫容錯代碼時並不能像Hystrix那樣作到那麼優雅統一!

5、後記

若是你能讀到這裏,恭喜你已經對微服務限流、熔斷這一關鍵問題有了從實踐層面最深入的體會了。

相關文章
相關標籤/搜索