SpringCloud Alibaba Sentinel 限流詳解

2022-05-29 21:01:54

點贊再看,養成習慣,微信搜尋【牧小農】關注我獲取更多資訊,風裡雨裡,小農等你,很高興能夠成為你的朋友。
專案原始碼地址:公眾號回覆 sentinel,即可免費獲取原始碼

熔斷規則

在上一篇文章中我們講解了流控規則的使用和介紹Sentinel流控規則,今天我們給大家講解sentinel更多樣化的講解以及流量控制。

官方檔案:https://sentinelguard.io/zh-cn/docs/circuit-breaking.html

在面對呼叫鏈路中不穩定的資源如何保證高可用?在微服務中一個服務通常會呼叫其他的模組,可能是服務內的某個應用也有可能是另外的一個遠端服務,資料庫或者其他API呼叫。比如我們在支付的時候會呼叫(某付寶、某信、某聯)提供的API,在查詢訂單我們會呼叫資料庫連線,這些依賴的服務有可能會存在系統不穩定的情況,如果依賴的服務出現了不穩定的情況,請求響應時間過長,執行緒資源產生堆積,可能最終會耗盡服務的資源,導致服務變的不可用,這個時候 熔斷降級 是保證服務高可用的重要措施之一。

如今的微服務都是分散式,有很多服務組成,不同服務之間互相呼叫,有著比較複雜的呼叫鏈路,在上面我們只是模擬繪畫了支付操作,在實際的鏈路呼叫過程中會有著放大效果,如果某一環不穩定,可能會形成 蝴蝶效應 最終導致整個鏈路響應時間過長,甚至不可用,所以如果當我們的服務出現 不穩定且沒有強依賴服務 呼叫的時,可以進行熔斷降級,暫時限制不穩定的呼叫,避免影響整體服務。

熔斷策略:

sentinel提供了三種熔斷策略

  • 慢呼叫比例: 選擇以慢呼叫比例作為閾值,需要設定允許的慢呼叫RT(最大響應時間),如果請求響應時間大於該值則認為慢呼叫,當統計時長內請求數 大於 最小請求數,且慢呼叫比例大於閾值,在熔斷時長內的請求會被自動熔斷,超過熔斷時長進入半恢復狀態(HALF_OPEN),如果下一個請求響應時間 小於 慢呼叫比例RT結束熔斷,否則再次熔斷。

  • 異常比例: 當統計時長內請求數 大於 最小請求數,且異常比例大於設定的閾值,在熔斷時間內請求自動熔斷,超過熔斷時長進入半恢復狀態(HALF_OPEN),如果下一個請求成功,結束熔斷,否則再次熔斷,異常比例閾值範圍(0.0-1.0)代表百分比。

  • 異常數: 當統計時長內異常數 大於 閾值,自動進行熔斷,超過熔斷時長進入半恢復狀態(HALF_OPEN),如果下一個請求成功,結束熔斷,否則再次熔斷。

熔斷狀態:

熔斷狀態 說明
OPEN 熔斷開啟,拒絕所有請求
HALF_OPEN 熔斷半開啟(恢復狀態),如果接下來請求成功結束熔斷,否則繼續熔斷
CLOSE 熔斷關閉,請求通過

熱點引數規則的核心屬性:

屬性(Field) 說明 預設值
resource 資源名(規則的作用物件 ) 必填
grade 熔斷策略(支援慢呼叫比例/異常比例/異常數策略) 必填 慢呼叫比例
count 慢呼叫比例模式下為慢呼叫臨界 RT(超出該值計為慢呼叫);異常比例/異常數模式下為對應的閾值
timeWindow 熔斷時長,單位為 s
minRequestAmount 熔斷觸發的最小請求數,請求數小於該值時即使異常比率超出閾值也不會熔斷(1.7.0 引入) 5
statIntervalMs 統計時長(單位為 ms),如 60*1000 代表分鐘級(1.8.0 引入) 1000 ms
slowRatioThreshold 慢呼叫比例閾值,僅慢呼叫比例模式有效(1.8.0 引入)

熔斷策略 - 慢呼叫比例

選擇以慢呼叫比例作為閾值,需要設定允許的慢呼叫RT(最大響應時間),如果請求響應時間大於該值則認為慢呼叫,當統計時長內請求數 大於 最小請求數,且慢呼叫比例大於閾值,在熔斷時長內的請求會被自動熔斷,超過熔斷時長進入半恢復狀態(HALF_OPEN),如果下一個請求響應時間 小於 慢呼叫比例RT結束熔斷,否則再次熔斷。

如果我們一秒鐘請求的數量大於5且RT(最大響應時間)大於我們設定的比例閾值的時候,觸發熔斷策略,比如我們有8個請求在一秒中進來,有5個慢呼叫,比例閾值設定為 0.1,這個時候我們滿足(QPS > 5 且 RT > 比例閾值),進入下一步熔斷策略,觸發熔斷器。

熔斷器的內部使用的是斷路器,這個好比我們做核酸,本來一棟一棟下去做,如果服務或者檢測機器蹦了,通知你暫時不要下來,當機器恢復了,再通知你下來做,這個就類似我們的斷路器。

案例演示:

    @GetMapping("/fuse")
    public String fuse(){
        try {
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "hello fuse";
    }

設定我們的熔斷策略,如果QPS>5請求RT>250且大於比例閾值觸發熔斷

通過JMeter測試,1秒鐘發起10個執行緒請求,此時就會觸發熔斷效果,停止測試以後,10秒鐘恢復正常

當我們啟動執行緒之後,再去存取fuse介面,可以看到被熔斷了,那麼當我們停止執行緒之後,十秒之後去存取,就可以正常存取

熔斷策略 - 異常比例

當統計時長內請求數 大於 最小請求數,且異常比例大於設定的閾值,在熔斷時間內請求自動熔斷,超過熔斷時長進入半恢復狀態(HALF_OPEN),如果下一個請求成功,結束熔斷,否則再次熔斷,異常比例閾值範圍(0.0-1.0)代表百分比。異常降級僅僅只針對業務異常,對於sentinel本身的異常不生效。

測試:

    @GetMapping("/exptoin")
    public String exptoin(Integer id){
        if(id != null && id > 1){
            throw new RuntimeException("異常比例測試");
        }
        return "exptoin test";
    }

接下來我們用JMeter進行測試,設定Http請求地址:http://localhost:8006/exptoin?id=5 當啟動JMeter的時候,會觸發熔斷,這個時候我們1秒鐘傳送10個請求超過了最小請求數,同事超過了閾值,滿足兩個條件,當熔斷時間結束 以後恢復正常

熔斷策略 - 異常數

當統計時長內異常數 大於 閾值,自動進行熔斷,超過熔斷時長進入半恢復狀態(HALF_OPEN),如果下一個請求成功,結束熔斷,否則再次熔斷。

測試程式碼:

    @GetMapping("/exptoin/num")
    public String exptoinNum(Integer id){
        if(id != null && id > 1){
            throw new RuntimeException("異常數測試");
        }
        return "exptoinNum test";
    }

設定異常數策略,當1秒鐘內請求超過5並且異常數大約5個的時候觸發熔斷

熱點規則

官網檔案:https://sentinelguard.io/zh-cn/docs/parameter-flow-control.html

什麼是熱點規則?熱點我們很好理解,就是很火的東西在程式中可以理解成頻繁存取的資料,那麼有時候我們系統通緝你某個熱點資料中存取頻次最高的 前幾個資料對其進行限制存取。

例如在秒殺系統中,某一款商品或者某幾款商品,要定點秒殺,我們可以以商品ID為引數,在一定時間內對其進行限流

又或者如果某一個使用者頻繁的去存取我們系統,我們也可以針對於使用者ID或者IP進行限制。

熱點規則會統計入參引數中的熱點資料,根據設定的限流閾值和模式,對啟動的熱點資料進行限流也就是流量控制。

在上圖中我們攜帶了 是三個引數(axb\abc\xs)等,我們在sentinel中設定熱點限流,我們設定的QPS為5,注意:該模式只支援QPS限制,如果我們的axb引數,命中了我們的規則,那麼該請求攜帶的引數就會被限流。

在使用熱點規則的時候,我們需要配合對應的@SentinelResource註解進行使用,才能夠達到更加細粒度的流控規則。

@SentinelResource

  • value:代表資源名稱,必填,通過name找到對應的規則
  • blockHandler: blockHandler 對應處理 BlockException 的方法名稱,可選項,存取範圍為public,返回型別需要和原方法匹配,並且在最後一需要新增BlockException型別的引數

測試程式碼:

    @GetMapping("/hotTest")
    @SentinelResource(value = "hotTest")
    public String testHotKey(@RequestParam(value = "v1",required = false) String v1,
                             @RequestParam(value = "v2",required = false)String v2){
        return "熱點規則 -  熱點:";
    }

在這裡我們要注意,我們需要設定的是不帶斜槓的資源名稱,這個才是我們需要設定的專案

這個時候我們傳入引數 http://localhost:8006/hotTest?v1,不停的重新整理瀏覽器,這個時候會超過閾值,那麼下面就會出現限流

但是,這個報錯資訊不是很友好,一般人根本不知道啥意思,我們可以使用@SentinelResource註解提供的另外一個引數blockHandler,這個引數是可以指定當出現異常時的處理方法,操作如下:

    @GetMapping("/hotTest")
    @SentinelResource(value = "hotTest",blockHandler = "handler_hot")
    public String testHotKey(@RequestParam(value = "v1",required = false) String v1,
                             @RequestParam(value = "v2",required = false)String v2){

        if("5".equals(v1)){
            throw new RuntimeException("報告有bug!!!");
        }
        return "熱點規則 -  熱點:";
    }
    
     //處理異常方法,方法簽名要和對應的介面方法保持一致
    public String handler_hot(String v1, String v2, BlockException exception){
        return "請求過於頻繁,請稍後再試.....";
    }

重新新增熱點規則後,再去頻繁的去存取,效果如下:

例外項數目

熱點規則除了上述的基礎使用外,還有例外項的操作,例外項引數可以達到更加細粒度的控制,比如我們在當前的案例中,目前v1引數在存取時超過閾值則會被限流,當時如果我們想通過引數v1等於具體的值的時候,來出發不同的流控效果時,改怎麼操作呢?

比如我想要讓v1等於2的時候,閾值達到50,其他的規則走上面的規則。

如果當前v1的值為2的時候,會走例外項裡面的設定,也就是50的閾值,如果不是2會走普通的閾值規則,通過下圖我們可以看到如果為2的值,無論我們點選多少次,都不會提示我們請求過於頻繁。

系統規則

sentinel系統自適應限流是從整體維度對應用入口流量進行控制,結合應用的 load、CPU使用率、總體平均RT、入口QPS和並行執行緒數等幾個維度的監控指標,通過自適應的流控策略,來讓系統入口流量和系統的負載達到一個平衡,讓系統儘可能的在面對高並行存取的同時保證系統整體的穩定。

系統保護是應用整體,所以不具備更細粒度的操作,只針對於入口流量有效。

系統規則支援的模式:

  • LOAD自適應: 針對於linxu/unix 機器有效,系統load(一分鐘平均負載)作為啟發指標,進行自適應系統保護。
  • RT:單臺機器上所有的入口流量平均RT達到閾值時,觸發系統保護,單位為毫秒
  • 執行緒數: 單臺機器上所有入口流量的並行執行緒數達到閾值觸發系統保護
  • 入口QPS: 單臺機器上所有入口流量的QPS達到閾值觸發系統保護
  • CPU 使用率: 當系統CPU使用率超過閾值時觸發系統保護(取值範圍:0.0 - 1.0)

演示:

通過入口QPS來進行測試,直接設定規則

最後測試效果不管現在我們存取那個介面只要超過閾值就會被限流

總結

到這裡我們限流策略就講完了,其實並不複雜,我們需要了解其中每個規則如何使用,效果是怎樣的,最好是自己動手試一試,會更有成就感。

我是牧小農,怕什麼真理無窮,進一步有進一步的歡喜,大家加油