Sentinel全局Feign默認熔斷設計實現


前言

上篇文章中介紹了Sentinel全局默認熔斷,留下了一個思考:

圖片

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

現在就會遇到這樣的問題,如果有很多Feign接口,如上圖服務A、服務B都有一些Feign接口的遠程調用,都需要我們進行一一配置。而且配置的一些參數絕大多數都一樣的。如:

1、對Feign遠程調用的慢響應策略的配置降級策略

2、對Feign遠程調用的異常數的配置降級策略

3、對Feign遠程調用的異常比例數的配置降級策略

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

雖然之前的文章中,我們已經解決了Feign的全局默認降級fallback配置,但是他沒法實現熔斷(即沒有熔斷功能,每次都要去調用異常服務方法,然后再降級)。

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

源碼分析

我們先來看看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默認熔斷的技術實現方案,整體思路原理不是太復雜,就是利用其本身的功能,做了一些擴展;這樣更方便用戶的使用。小伙伴如果需要源代碼可以聯系哦。謝謝!!!

java高級開發系統進階筆記、最新面試復習筆記PDF,我的GitHub


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM