Sentinel全域性Feign預設熔斷設計實現

阿風的架構筆記發表於2021-04-14

寫在前面

用XMind畫了一張導圖記錄Spring Cloud Alibaba的學習筆記(原始檔對部分節點有詳細備註和參考資料,由於太大就沒展示全部,歡迎關注我的公眾號:阿風的架構筆記 後臺傳送【導圖】拿下載連結, 已經完善更新):

前言

思考這個問題:

圖片

Sentinel的降級熔斷的配置,生產環境使用的時候,一般會在控制檯管理,持久化到Nacos;微服務監聽Nacos的配置變化,從而實現服務呼叫的降級熔斷策略。

現在就會遇到這樣的問題,如果有很多Feign介面,如上圖服務A、服務B都有一些Feign介面的遠端呼叫,都需要我們進行一一配置。而且配置的一些引數絕大多數都一樣的。如:

1、對Feign遠端呼叫的慢響應策略的配置降級策略

2、對Feign遠端呼叫的異常數的配置降級策略

3、對Feign遠端呼叫的異常比例數的配置降級策略

針對上面的配置1-2個服務方法還好;但是現在公司的生產環境都有100~200個微服務,服務之間的呼叫方法就更多了;那針對普通標準的降級熔斷的配置都需要人工一個個配置,那是不是太麻煩了。

本文就來解決這個問題,跟著繼續往下看。

原始碼分析

我們先來看看Sentinel是怎麼設定熔斷策略的,在上圖中我們知道是通過Sentinel控制檯進行配置,然後微服務都可以訂閱這些配置;我們看一下原始碼。

圖片

這個是監聽nacos配置的相關的程式碼

圖片

上圖程式碼核心就是發現配置有變化,就updateValue規則;我們繼續跟蹤程式碼發現一個DegradeRuleManager降級規則的管理類,裡面有2個核心的變數ruleMap、circuitBreakers;我們可以猜出就是降級規則集合以及熔斷規則集合。

圖片

在繼續往下看,我們發現有個RulePropertyListener中reloadFrom方法****,即重新載入規則;方法裡面有個buildCircuitBreakers方法,一看方法名就知道是構建熔斷策略。

圖片

在看一下buildCircuitBreakers方法,我們看到本質就是遍歷DegradeRule集合,然後在初始化熔斷物件CircuitBreaker。

圖片

這裡我們知道熔斷是怎麼產生的了;本質就是通過DegradeRule產生的。

解決方案

上面我們知道了一些熔斷物件產生的原理,我們只要可以自定義DegradeRule物件就可以產生。我們在學習Sentinel的時候,他有個Api方式去定義降級規則,大家可以去看一下之前的文章,詳細介紹了Api定義規則的方式。我們看一下案例

圖片

我們可以看到DegradeRule物件的定義,以及DegradeRuleManager物件;上面的程式碼就能給資源名api定義了慢響應的降級策略了

講到這裡聰明的小夥伴們有沒有想到一些思路呢?往下看。

方案思路

先給出整體的解決思路

圖片

上圖中介紹的流程

1、啟動服務時掃描jar,獲取@FeignClient註解的介面(技術難點一:掃描哪些jar包)
2、獲得Feign介面中的呼叫方法
3、服務本地建立DegradeRule物件。(技術難點二:Sentinel的資源名支援動態配置)
4、把設定的預設的降級熔斷規則同步到Nacos

根據上面的流程,我們就可以看到,一旦微服務啟動了,就會自動把Feign介面配置預設的降級熔斷規則,以及同步到Nacos中;再結合之前文章中介紹的Sentinel控制檯改造,就立刻在控制檯顯示這些降級規則了,而不需要認為配置了。

注意:上面只是介紹了整體流程,在編寫程式碼的時候,我們需要考慮到很多場景,如:

一)服務第二次啟動的時候,nacos中已經有了相關的配置,是否還要修改nacos的配置。

二)以及有些特殊業務在Sentinel控制檯進行了降級配置,那預設的全域性配置如何相容人工的配置。

這些就不在這裡講了,本文只介紹核心方案思路,核心程式碼

其他的有興趣的小夥伴們,可以跟要原始碼

技術難點

難點一

我們掃碼jar包,而且是要掃碼包含@FeignClient註解介面的jar。我們知道在使用Feign功能的時候,需要在SpringBootApplication啟動類中加上@EnableFeignClients;

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

有的時候Feign包會用第三方jar的形式存在,那程式碼就有會變成

@SpringBootApplication
@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.rainbow.demo1.feign","com.rainbow.demo2.feign"})
public class ApplicationA {
  public static void main(String[] args) {
    SpringApplication.run(ApplicationA.class, args);
  }
}

裡面的@EnableFeignClients註解的屬性basePackages中顯式的指向了Feign包的位置了,這個比較好弄,直接用用ClassScan工具類掃就行了。

ClassScan工具類是支援子包掃描的

那沒有顯式的定義basePackages,那怎麼獲取到jar包路徑呢?

我們可以參考SpringCloud的原始碼實現的方法,看程式碼。

圖片

上面是根據啟動服務時,堆疊資訊獲取main方法的啟動類物件。

圖片

根據啟動類物件,獲取到EnableFeignClients物件,如果沒有basePackages,那就是以啟動類的包為掃描的入口。

這樣我們就解決了掃描jar入口的問題。

難點二

常規方式

資源名的獲取,舉個例子

@FeignClient(name = "service-provider")
public interface ProviderServiceFeign {
    @GetMapping("/transferHeaders")
    public BaseRestResponse<String> transferHeaders();
}

根據微服務的Sentinel資源名定義,@FeignClient(name = "service-provider"),微服務名是service-provider;那針對transferHeaders()方法的降級策略資源名即為

lb://service-provider/transferHeaders

這個實現比較簡單就是獲取@FeignClient的name的值,以及方法@GetMapping裡面的值就可以拼接出資源名。

指定Url地址

@FeignClient(name = "service-provider",url = "http://xxxxx")
public interface ProviderServiceFeign {
    @GetMapping("/transferHeaders")
    public BaseRestResponse<String> transferHeaders();
}

指定url的目的其實就是指定請求的方式,這種情況的Sentinel的資源名即為

http://xxxxx/transferHeaders

這個技術實現也比較簡單,只需要考慮到這個場景,就可以了。

動態配置Url

還有一種情況即對接第三方平臺時,我們一般不會寫死Url,而是通過配置的方式,如

@FeignClient(name = "service-provider",url = "${reqUrl}")
public interface ProviderServiceFeign {
    @GetMapping("/transferHeaders")
    public BaseRestResponse<String> transferHeaders();
}

上面的${reqUrl}是通過配置的,那Sentinel的資源名是什麼樣的呢?本質上面資源名也是Url+具體的請求地址,即

http://${reqUrl}/transferHeaders

但是這樣設定資源名肯定是不正確的,需要把具體的配置值拿過來拼接。那我們就需要在程式中獲取${reqUrl}的值,講到這裡小夥伴們知道怎麼實現了嗎?其實就是用到

Environment environment ;//環境變數物件
this.environment.resolvePlaceholders(url);//獲取變數的值

圖片

核心程式碼

上面的技術難點解決掉之後,我們就放開雙手擼程式碼了,這裡貼上核心的程式碼;小夥伴們。

public class DegradeRuleInitializer implements ApplicationRunner, EnvironmentAware

實現ApplicationRunner, EnvironmentAware就能夠實現啟動時,去掃描了,入口就在ApplicationRunner中的run方法。

圖片

掃描類

圖片

掃描FeignClient

圖片

初始化預設規則

圖片

設定了預設降級規則,把配置資訊釋出到nacos

圖片

效果

一旦微服務啟動了,nacos配置就有了

圖片

我們會把預設的值釋出到nacos裡面,小夥伴們可以具體看一些資源名,裡面就會有很多降級規則。

圖片

我們再來看看Sentinel控制檯,裡面就顯示了降級規則列表;設計的是針對同一個資源名做異常數、異常比例、慢響應三種型別的降級熔斷策略。

圖片

全域性預設的值,到底是多少閥值,是可以通過配置的方式的,這些就不介紹了。比較簡單。

到這裡就全部實現了微服務中Feign介面的降級熔斷策略的預設化配置,不需要人工去新增了;當然是支援人工去修改的,如果需要修改閥值,可以人工修改。

總結

本文介紹了Sentinel的全域性Feign預設熔斷的技術實現方案,整體思路原理不是太複雜,就是利用其本身的功能,做了一些擴充套件;這樣更方便使用者的使用。

看完三件事❤️


如果你覺得這篇內容對你還蠻有幫助,我想邀請你幫我三個小忙:

  1. 點贊,轉發,有你們的 『點贊和評論』,才是我創造的動力。
  2. 關注公眾號 『 阿風的架構筆記 』,不定期分享原創知識。
  3. 同時可以期待後續文章ing?
  4. 關注後回覆【666】掃碼即可獲取架構進階學習資料包

相關文章