Sentinel自定義流控兜底,異常兜底,鏈路失效,踩坑總結~


想一口吃個胖子是不可能了,本來想快速過一遍alibaba,做個項目熟悉一下再深入研究,搞到Sentinel時遇到一些問題。

首先是流控模式中的鏈路模式時效問題,無法正確的再控制台顯示和流控。已經通過 https://github.com/alibaba/Sentinel/issues/1213  改好了。親測可用,我的 sentinel-1.7.1,項目client里用的2.2.0。

下班了,不寫了,明天再寫哈哈哈。

上班了,繼續!

先說鏈路的問題。

眾所周知懶加載的sentinel dashboard 上面會展示調用過的接口信息,然后鏈路綁定時展示不全,如下

Controller中有兩個接口,他們同時調用了Service的方法

    @Autowired
    private TestService testService;

    @GetMapping("/link1")
    public ResponseEntity<String> link1() {
        return ResponseEntity.ok(
                String.format("link1,調用test,結果為%s", testService.hello()));
    }

    @GetMapping("/link2")
    public ResponseEntity<String> lin2() {
        return ResponseEntity.ok(
                String.format("link2,調用test,結果為%s", testService.hello()));
    }

又將hello方法注冊到了sentinel中,這里先不看兜底的方法問題,先解決了這個鏈路限流失敗的問題。

@Service
public class TestService {
    @SentinelResource(value = "hello", 
  blockHandlerClass = SentinelHandlersClass.class, blockHandler = "handleException",
  fallbackClass = SentinelHandlersClass.class,fallback = "handleError") public String hello() { return "hello"; } }

這樣調用在sentinel中顯示為

 很明顯沒有展示全,這就導致了后面一列的問題發生了,使用鏈路限流會失效的問題。

解決方法從github上看過了,在這里記錄一下

導包

<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-web-servlet</artifactId>
</dependency>

至於為什么這么寫還沒有研究,待更....

@Configuration
public class FilterContextConfigSentinel {
    /**
     * @NOTE 在spring-cloud-alibaba v2.1.1.RELEASE及前,sentinel1.7.0及后,關閉URL PATH聚合需要通過該方式,spring-cloud-alibaba v2.1.1.RELEASE后,可以通過配置關閉:spring.cloud.sentinel.web-context-unify=false
     * 手動注入Sentinel的過濾器,關閉Sentinel注入CommonFilter實例,修改配置文件中的 spring.cloud.sentinel.filter.enabled=false
     * 入口資源聚合問題:https://github.com/alibaba/Sentinel/issues/1024https://github.com/alibaba/Sentinel/issues/1213
     * 入口資源聚合問題解決:https://github.com/alibaba/Sentinel/pull/1111
     */
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口資源關閉聚合
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}

我們重啟測試一下

 只要鏈路能正常展示了又搞了一下鏈路限流完全ok了啊。

下面開始說兜底的事。一點一點屢。

先貼一下兜底的代碼

注意

  1.兜底方法的參數要和被的兜底方法的一樣

  2.返回值要和被兜底方法的返回值一樣

  3.限流兜底方法的   BlockException blockException 必須要有,異常兜底的  Throwable blockException  參數好像不是必須,但是沒寫他也沒找到異常兜底。

  4.方法必須是public static 修飾。

public class SentinelHandlersClass
{
//限流時的兜底處理 public static ResponseEntity<String> handleException(BlockException blockException) { return ResponseEntity.ok("兜底了"); } //異常兜底 public static ResponseEntity<String> handleError(Throwable blockException) { return ResponseEntity.ok("兜底了,異常"); } }
@SentinelResource(value = "link1", 
blockHandlerClass = SentinelHandlersClass.class, //限流兜底方法所在類
blockHandler = "handleException", //限流時兜底方法
fallbackClass = SentinelHandlersClass.class, //異常兜底放方法所在類
fallback = "handleError") //異常時兜底

大概解釋了一下,我們測試一下,目前是這樣配置的

 然后他展示的是這樣,感覺亂七八糟的,

 代碼里/link1的  @SentinelResource 注解有value屬性,那就是他在sentinel的資源名,而/link2沒有所以給了個默認,然后測試了一下各個資源名的流控都沒問題。問題是都不走兜底處理,只有link1走了流控,連/link1的資源都不走,再吐槽一下/link2的資源名默認給的那個,完全錯誤了,回頭看一下源碼。

 以上三個都不走兜底處理,再展示一下link1。

 

 當一秒內訪問超過兩次走兜底方法,而不是默認的429異常了。

然后再展示一種情況,有關於這個兜底的問題文章不是很多,有網友說把@RequestMapping和資源名@SentinelResource的value設置成一樣的,我們也試一下。

 

 然后我們來做限流,直接給第二個/link1做。神奇的事情發生了,/link1接口會直接返回兜底內容,限流以后又返回了默認的429錯誤。

如圖

 

 

 

這就是親愛的網友給大家留的坑,可能他們在抄博客的時候也沒動什么腦子,給萌新留坑,污染環境。另外不吐槽原創了,可能版本不一樣,我的版本貼在文章開頭了。

所以找不到兜底方法或者不執行兜底方法的問題不在乎接口名和資源名是否相同。改回來以后就沒問題了。需要注意要給資源名做限流,不要給默認的做限流,這樣還是會找不到兜底處理。

異常兜底一樣。

 現在再測試一下下層的hello方法,給他做限流會返回什么呢。

 

 這里做了兩個限流,一個是直接限流hello,另一個是做了鏈路限流,如圖,當hello超過訪問量限制link1的訪問

 測試以后也和普通的一層接口不同,兩個限流都是直接走異常兜底的。

結束!再見

 


免責聲明!

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



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