天天看點

JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

Spring Cloud Alibaba學習筆記

  • Sentinel流量防衛兵
    • Sentinel 簡介
      • 官方介紹
      • 總結
    • 服務降級
      • 降級實作方式分類
      • Sentinel 式方法級降級
      • Sentinel 式類級降級
      • Feign 式類級降級
    • Sentinel Dashboard
      • 簡介
      • 下載下傳
      • 啟動
      • 通路
    • 服務熔斷
      • 熔斷概念
      • 動态設定
      • 熔斷政策
        • 慢調用比例
        • 異常比例
        • 異常數
      • 代碼設定
    • 服務流控
      • 流控概念
      • 動态設定
        • 設定方法一
        • 設定方法二
      • 代碼設定
        • 使用注解
        • 不使用注解
      • 門檻值類型分類
        • QPS流控超值處理方案
        • 并發線程數流控方案
      • 流控模式分類
        • 直接
        • 關聯
        • 鍊路
      • 流控效果分類
        • 快速失敗
        • Warm Up
        • 排隊等待
        • 限流算法(回顧)
      • 流控方案代碼設定
        • 線程隔離流控
        • QPS 預設流控
        • 關聯流控模式
        • 鍊路流控模式
        • WarmUp 流控
        • 排隊等待流控
    • 來源流控
      • 概念
      • 定義原始請求解析器
      • 流控規則中的來源指定
      • 動态設定黑白名單
      • 代碼設定黑白名單

Sentinel流量防衛兵

Sentinel 簡介

官方介紹

  • wiki位址:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

總結

  • Sentinel 是分布式系統的防禦系統。以流量為切入點,通過動态設定的流量控制、服務熔斷等手段達到保護系統的目的,通過服務降級增強服務被拒使用者的體驗。

服務降級

  • 服務降級是一種增強使用者體驗的方式。當使用者的請求由于各種原因被拒後,系統傳回一個事先設定好的、使用者可以接受的,但又令使用者并不滿意的結果。這種請求處理方式稱為服務降級。

降級實作方式分類

對于 Sentinel,服務降級的實作方式根據消費者類型的不同,其支援兩種方式:

  • Sentinel 式降級:通過 Sentinel 自身的 API 實作的降級方式,适用于任意消費者類型。而根據降級方法應用範圍、定義位置及可維護性的不同,又可分為兩種:
    • 方法級降級:降級方法與原方法定義在同一個類中,其僅是本類中的原方法可以使用。
    • 類級降級:降級方法定義在專門的一個類中,其是一個可以被共享的降級類。該類中的所有方法均為降級方法,是以便于維護與管理。
  • Feign 式降級:通過 OpenFeign 的 API 實作的降級方式,僅适用于 Feign 用戶端的消費者類型,其隻有類級降級方式。

Sentinel 式方法級降級

  • 建立工程:複制 02-consumer-nacos-8080 工程,重命名為 06-consumer-sentinel-degrade-method-8080。
  • 引入依賴:
<!-- sentinel 依賴 -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
           
  • 修改處理器:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試位址:http://localhost:8080/consumer/depart/get/1

Sentinel 式類級降級

  • 建立工程:複制 06-consumer-sentinel-degrade-method-8080,重命名為 06-consumer-sentinel-degrade-class-8080。
  • 定義降級類:
/**
 * 自定義降級類
 */
public class DepartServiceFallback {
    public static Depart findByIdFallback(int id, Throwable e) {
        return new Depart()
                .setId(id)
                .setName("degrade-class-" + id + "-" + e.getMessage());
    }

    public static List<Depart> listFallback() {
        return Collections.singletonList(new Depart().setName("no any depart"));
    }
}
           
  • 修改處理器:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試位址:http://localhost:8080/consumer/depart/get/1、http://localhost:8080/consumer/depart/list

Feign 式類級降級

  • 建立工程:複制 04-consumer-feign-8080 工程,并重命名為 06-consumer-sentinel-degrade-feign-8080。這個消費者是通過 Feign 接口進行消費的。
  • 添加依賴:
<!-- sentinel 依賴 -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
           
  • 修改配置檔案:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 定義降級類:
/**
 * 自定義降級類
 */
@Slf4j
@Component
@RequestMapping("/fallback/consumer/depart") // 必須以 /fallback 開頭
public class DepartServiceFallback implements DepartService { // 實作Feign接口

    @Override
    public boolean save(Depart depart) {
        log.info("執行save()的服務降級處理方法");
        return false;
    }

    @Override
    public boolean deleteById(int id) {
        log.info("執行deleteById()的服務降級處理方法");
        return false;
    }

    @Override
    public boolean update(Depart depart) {
        log.info("執行update()的服務降級處理方法");
        return false;
    }

    @Override
    public Depart findById(int id) {
        log.info("執行findById()的服務降級處理方法");
        return new Depart()
                .setId(id)
                .setName("degrade-feign");
    }

    @Override
    public List<Depart> list() {
        log.info("執行list()的服務降級處理方法");
        return Collections.singletonList(new Depart().setName("no any depart"));
    }
}
           
  • 修改 Feign 接口:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

Sentinel Dashboard

簡介

  • Sentinel Dashboard 是 Sentinel 的一個輕量級開源 GUI 控制台,可以提供對 Sentinel 主機(Sentinel 應用)的發現及健康管理、動态配置服務流控、熔斷、路由規則的配置與管理。
  • 官方文檔github位址:https://github.com/alibaba/Sentinel/wiki/%E6%8E%A7%E5%88%B6%E5%8F%B0
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

下載下傳

  • 直接從官方下載下傳打包好的 Sentinel Dashboard 啟動運作,下載下傳位址:https://github.com/alibaba/Sentinel/releases
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
wget https://github.com/alibaba/Sentinel/releases/download/v1.8.0/sentinel-dashboard-1.8.0.jar
           

啟動

  • 啟動 Sentinel 控制台需要 JDK 版本為 1.8 及以上版本。
  • 啟動指令:
java -Dserver.port=8888 -Dcsp.sentinel.dashboard.server=localhost:8888 -Dproject.name=sentinel-dashboard -Dsentinel.dashboard.auth.username=sentinel -Dsentinel.dashboard.auth.password=123456 -jar sentinel-dashboard-1.8.0.jar
           

通路

  • 位址:http://192.168.254.130:8888
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

服務熔斷

熔斷概念

  • 參看之前的部落格:JavaEE 企業級分布式進階架構師(十三)微服務架構 SpringCloud (G 版)(3)

動态設定

  • 對于服務熔斷規則,一般是提前設定好的,可以通過 Sentinel Dashboard 進行動态設定。
  • 建立工程:複制 06-consumer-sentinel-degrade-method-8080 工程,重命名為 06-consumer-sentinel-circuitbreaking-8080。
  • 修改處理器類:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 修改配置檔案:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 修改提供者工程:使用之前的 04-provider-nacos-8081 工程
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 啟動提供者工程、消費者工程之後,此時通路 http://localhost:8080/consumer/depart/get/1 是沒有問題的。
  • 打開 Sentinel dashboard 設定規則:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試位址:http://localhost:8080/consumer/depart/get/1,在浏覽器不斷重新整理,測下熔斷降級效果。

熔斷政策

慢調用比例

  • 該政策需要設定用于界定慢調用的響應時間門檻值 RT(Response Time),當請求的響應時間大于該值時,将該請求統計為慢調用。若要發生熔斷,在 1 秒内收到的請求數量不能小于“最小請求數”,且慢調用占比不能低于“比例門檻值”。當觸發熔斷,則會在“熔斷時長”内不再對請求進行處理,即熔斷期間再來的請求,将直接進行降級響應。

異常比例

  • 該政策需要設定異常請求在統計時間視窗内所有請求中的占比,異常比率的門檻值範圍是 [0.0, 1.0],代表 0% - 100%。當異常請求比例大于該值時則會觸發熔斷。預設情況下,統計時間視窗大小為 1 秒,期間接收到的請求至少 5 個。發生熔斷後,熔斷時長為指定的時長。熔斷期間再來的請求,将直接地降級響應。

異常數

  • 該政策需要設定在統計時間視窗内所接收到的異常請求的數量。當異常請求數量大于該值時則會觸發熔斷。預設情況下,統計時間視窗大小為 1 分鐘,注意,是 1 分鐘。發生熔斷後,熔斷時長為指定的時長。熔斷期間再來的請求,将直接地降級響應。

代碼設定

  • 通過 Dashboard 平台進行熔斷規則設定,粒度有些粗,有些屬性隻能通過代碼來設定。而代碼中的 API,在不同的 Sentinel 版本中,是有所不同的。
  • 熔斷規則直接定義在代碼中,當應用啟動時完成熔斷規則的建立與初始化。這個熔斷規則在 Dashboard 中也是可以檢視到并且進行編輯的,編輯後以動态編輯的規則為準。
  • 下面直接在 06-consumer-sentinel-circuitbreaking-8080 工程中修改示範。在啟動類中添加對熔斷規則的定義與設定代碼。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Consumer068080 {
    public static void main(String[] args) {
        SpringApplication.run(Consumer068080.class, args);
        // 初始化規則
        initRule();
    }

    private static void initRule() {
        List<DegradeRule> rules = new ArrayList<>();
        rules.add(slowRequestDegradeRule());
        DegradeRuleManager.loadRules(rules);
    }

    private static DegradeRule slowRequestDegradeRule() {
        // 建立一個降級規則執行個體
        DegradeRule rule = new DegradeRule();
        // 指定該規則要應用的資源名稱
        rule.setResource("findById");
        // 指定熔斷規則為:慢調用比例
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        // 設定門檻值:RT的時間,機關毫秒。若一個請求擷取到響應時間超出該值,則會将該請求統計為"慢調用"
        rule.setCount(200);
        // 設定熔斷視窗大小,機關秒
        rule.setTimeWindow(30);
        // 設定最小請求數量
        rule.setMinRequestAmount(5);
        // 設定發生慢調用的比例
        rule.setSlowRatioThreshold(0.5);
        return rule;
    }

    private static DegradeRule exceptionRatioDegradeRule() {
        DegradeRule rule = new DegradeRule();
        rule.setResource("findById");
        // 指定熔斷規則為:異常比例
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO);
        // 設定門檻值:發生熔斷的異常請求比例
        rule.setCount(0.5);
        rule.setTimeWindow(60);
        rule.setMinRequestAmount(5);
        return rule;
    }

    private static DegradeRule exceptionCountDegradeRule() {
        DegradeRule rule = new DegradeRule();
        rule.setResource("findById");
        // 指定熔斷規則為:異常數
        rule.setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT);
        // 設定門檻值:發生熔斷的異常請求比例
        rule.setCount(5);
        rule.setTimeWindow(60);
        rule.setMinRequestAmount(5);
        return rule;
    }
}
           

服務流控

流控概念

  • 流控,即流量控制,也稱為限流。Sentinel 實作流控的原理是監控應用流量的 QPS 或并發線程數等名額,當達到指定的門檻值時對再來的請求進行進行控制,以避免被瞬時的流量高峰沖垮,進而保障應用的高可用性。

動态設定

  • 流控規則直接通過 Sentinel Dashboard 定義,該規則可以随時修改而不需要重新開機應用該規則的應用程式。是以這種流控是一種動态流控。
  • 建立工程:複制 06-consumer-sentinel-degrade-method-8080 工程,并重命名為 06-consumer-sentinel-flowcontrol-8080。
  • 修改配置檔案,增加 Sentinel dashboard 的配置。

設定方法一

  • 修改處理器:指定流控規則
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • dashboard 設定流控規則:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試位址:http://localhost:8080/consumer/depart/get/1,在浏覽器不斷重新整理,測下流控效果。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

設定方法二

  • 修改處理器:添加流控處理方法
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試位址:http://localhost:8080/consumer/depart/get/1,在浏覽器不斷重新整理,測下流控效果。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

代碼設定

使用注解

  • 流控規則直接定義在代碼中,當應用啟動時完成流控規則的建立與初始化。這個流控規則在 Dashboard 中也是可以檢視到并且進行編輯的,編輯後以動态編輯的規則為準。
  • 直接在 06-consumer-sentinel-flowcontrol-8080 工程啟動類中進行修改示範。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Consumer068080 {
    public static void main(String[] args) {
        SpringApplication.run(Consumer068080.class, args);
        initFlowRule();
    }

    private static void initFlowRule() {
        List<FlowRule> rules = new ArrayList<>();
        rules.add(qpsFlowRule());
        FlowRuleManager.loadRules(rules);
    }

    private static FlowRule qpsFlowRule() {
        FlowRule rule = new FlowRule();
        rule.setRefResource("qpsFlowRule");
        rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
        rule.setCount(1);
        // 值為default,表示對請求來源不做限定
        rule.setLimitApp("default");
        return rule;
    }
}
           

不使用注解

  • 流控規則在代碼中的應用,一般是通過@SentinelResource 指定的。但也可以通過代碼指定。隻不過這種方式不提倡使用。
  • 直接在 06-consumer-sentinel-flowcontrol-8080 工程啟動類中進行修改示範。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

門檻值類型分類

  • 流量控制主要有兩種門檻值統計類型,一種是 QPS,一種是統計并發線程數。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

QPS流控超值處理方案

  • QPS:Queue Per Second,就是通常所說的每秒的通路量。該流控方案通過對每秒通路量的控制來達到保護。當指定資源的每秒通路量達到了設定的門檻值時,可以立即拒絕再新進入的請求。

并發線程數流控方案

  • 并發線程數流控方案通常是對消費者端的配置。是為了避免由于慢調用而将消費者端線程耗盡情況的發生,業内會使用隔離方案。一般來說可以分為兩種:
  • 線程池隔離:系統為不同的提供者資源設定不同的線程池來隔離業務自身之間的資源争搶。該方案隔離性較好,但需要建立的線程池及線程數量太多,系統消耗較大。當請求線程到達後,會從線程池中擷取到一個新的執行線程去完成提供者的調用。由請求線程到執行線程的上下文切換時間開銷較大,特别是對低延時調用有比較大的影響。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 信号量隔離:系統為不同的提供者資源設定不同的計數器。每增加一個該資源的調用請求,計數器就變化一次。當達到該計數器門檻值時,再來的請求将被限流。該方式的執行線程與請求線程是同一個線程,不存線上程上下文切換的問題。更不存在很多的線程池建立與線程建立問題。也正因為請求線程與執行線程沒有分離,是以,其對于提供者的調用無法實作異步,執行效率降低,且對于依賴資源的執行逾時控制不友善。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • Hystrix 官方原理圖:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • Sentinel 隔離方案:Sentinel 并發線程數控制也屬于隔離方案,但不同于以上兩種隔離方式,是對以上兩種方案的綜合與改進,或者說更像是線程池隔離。其也将請求線程與執行線程進行了分離,但不負責建立和管理線程池,而僅僅是簡單統計該資源的請求占用的線程數量超出了門檻值,則可以立即拒絕再新進入的請求。

流控模式分類

JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

直接

  • 當對“資源名”指定資源的請求達到了設定門檻值時,再新進入的請求将被直接執行指定的“流控效果”。

關聯

  • 該模式比較特殊:當對别人的通路達到自己設定的門檻值時,将開啟對自己的限流。确切地說是,當對“關聯資源”的通路達到了“單機門檻值”指定的門檻值時,會對目前的資源通路進行限流。
  • 示例:直接修改 06-consumer-sentinel-flowcontrol-8080 工程的 DepartController 類
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 新增流控規則:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 修改之前的流控規則:當對 qpsFlowRuleList 這個資源的通路達到了門檻值1時,将會對 qpsFlowRule 這個資源進行限流
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試:使用Postman 并發請求 http://localhost:8080/consumer/depart/list,50個請求每個相隔200ms。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 然後通路 http://localhost:8080/consumer/depart/get/1,驗證下限流效果:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

鍊路

  • 當對一個資源有多種通路路徑時,可以對某一路徑的通路進行限流,而其它通路路徑不限流。
  • 示例:複制 02-provider-nacos-8081 工程,重命名為 06-provider-sentinel-flowcontrol-8081。
  • 添加依賴:
<dependency>
  <groupId>com.alibaba.csp</groupId>
  <artifactId>sentinel-web-servlet</artifactId>
  <version>1.7.0</version>
</dependency>
<!-- sentinel 依賴 -->
<dependency>
  <groupId>com.alibaba.cloud</groupId>
  <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>
           
  • 修改配置檔案:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 修改業務接口實作類:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 修改 DepartController:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 定義一個配置類:
@Configuration
public class FilterContextConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 預設情況下,Sentinel Web Filter收斂所有URL入口的Context
        // 解釋:例如 /list 和 /all 這兩個接口對 qpsFlowRule 資源的通路,對于整個系統是區分不開的
        // 這裡設定關閉URL入口收斂功能,這樣就可以區分
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}
           
  • 新增流控規則:先啟動 06-provider-sentinel-flowcontrol-8081 工程
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試:分别重新整理通路 http://localhost:8081/provider/depart/list 和 http://localhost:8081/provider/depart/all,看下限流效果。雖然 /list 和 /all 通路的是相同的資源,但是 /list 不發生限流,/all 發生限流。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

流控效果分類

快速失敗

  • 快速失敗,也稱為直接拒絕,是預設的 QPS 流控超值處理方式。當 QPS 超過設定的門檻值後,再來的請求将被直接拒絕,即抛出 FlowException。我們前面的流控使用的就是這種處理方式。
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

Warm Up

JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 當系統中某 service 的 QPS 長期處于低水位運作狀态時,系統為該 service 所配置設定的各種軟硬體資源都會很少,例如,緩存空間、線程數量等資源。若 QPS 陡然增加可能會将系統一下壓垮。為了避免這種情況的發生,我們希望 QPS 緩步增加到設定的門檻值。這種應急情況的處理方式稱為 warm up,即預熱,也稱為冷啟動。
  • sentinel 的 WarmUp 流控算法,采用的是 Guava 的 SmoothWarmingUp 算法,該算法繼承自 SmoothRateLimiter 算法。不過,它們的算法思路是不同的:
    • SmoothWarmingUp:其是通過不斷縮短請求間的間隔來達到逐漸提升通路量的目的。
    • Sentinel 的 WarmUp:其是通過不斷提升 QPS 來達到逐漸提升通路量的目的。其算法更像是令牌桶限流算法。

排隊等待

  • 排隊等待,也稱為勻速排隊。該方式會嚴格控制請求通過的間隔時間,讓請求以均勻的速度通過。其是漏鬥算法的改進。不同的是,當流量超過設定門檻值時,漏鬥算法會直接将再來的請求丢棄,而排隊等待算法則是将請求緩存起來,後面慢慢處理。不過,該算法目前暫不支援 QPS 超過 1000 的場景。
  • 其适合處理間隔性突發流量的場景。是削峰填谷效果的展現。

限流算法(回顧)

  • 令牌桶限流算法:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 漏鬥限流算法
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

流控方案代碼設定

  • 直接修改 06-consumer-flowcontrol-code-8080 工程。

線程隔離流控

private static FlowRule threadFlowRule() {
    FlowRule rule = new FlowRule();
    rule.setResource("threadFlowRule");
    rule.setGrade(RuleConstant.FLOW_GRADE_THREAD);
    rule.setCount(20);
    rule.setLimitApp("default");
    return rule;
}
           

QPS 預設流控

private static FlowRule qpsFlowRule() {
    FlowRule rule = new FlowRule();
    rule.setRefResource("qpsFlowRule");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setCount(1);
    rule.setLimitApp("default");
    return rule;
}

           

關聯流控模式

private static FlowRule qpsRelateFowRule() {
    FlowRule rule = new FlowRule();
    rule.setResource("qpsRelateFowRule");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setCount(1);
    rule.setStrategy(RuleConstant.STRATEGY_RELATE);
    rule.setRefResource("/list");
    rule.setLimitApp("default");
    return rule;
}
           

鍊路流控模式

private static FlowRule qpsChaniFlowRule() {
    FlowRule rule = new FlowRule();
    rule.setResource("qpsChaniFlowRule");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setCount(1);
    rule.setStrategy(RuleConstant.STRATEGY_CHAIN);
    rule.setRefResource("/provider/depart/list");
    rule.setLimitApp("default");
    return rule;
}
           

WarmUp 流控

private static FlowRule qpsWarmUpFlowRule() {
    FlowRule rule = new FlowRule();
    rule.setResource("qpsWarmUpFlowRule");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setLimitApp("default");
    rule.setCount(20);
    rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_WARM_UP);
    rule.setWarmUpPeriodSec(5);
    return rule;
}
           

排隊等待流控

private static FlowRule qpsQueueFlowRule() {
    FlowRule rule = new FlowRule();
    rule.setResource("qpsQueueFlowRule");
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setLimitApp("default");
    rule.setControlBehavior(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER);
    rule.setCount(20);
    rule.setMaxQueueingTimeMs(20 * 1000);
    return rule;
}
           

來源流控

概念

  • 來源流控:來源流控是針對請求發出者的來源名稱所進行的流控。在流控規則中可以直接指定該規則用于限流的來源名稱的請求,一條規則可以指定一個限流的來源。當然,若要指定多個來源,可以定義多個同名規則,也可以通過黑白名單規則一次性指定。
  • 黑白名單:無論是黑名單還是白名單,其實就是一個請求來源名稱清單,當然,該名單是屬于某一具體資源的。出現在黑名單中的來源請求将被降級,其它來源的請求則可以正常進行通路;出現在白名單中的來源請求是可以進行正常通路的,而其它來源請求則将被降級。

定義原始請求解析器

  • 建立工程:複制 06-consumer-sentinel-degrade-method-8080 工程,重命名為 06-consumer-sentinel-reqsource-8080。
  • 定義解析器:
/**
 * 定義原始請求解析器,其用于從請求中擷取 來源辨別
 */
@Component
public class DepartRequestOriginParser implements RequestOriginParser {
    /**
     * 該方法的傳回值即為請求來源辨別
     */
    @Override
    public String parseOrigin(HttpServletRequest request) {
        String source = request.getParameter("source");
        if (StringUtils.isEmpty(source)) {
            return "serviceA";
        }
        // 傳回的就是來源辨別
        return source;
    }
}
           
  • 修改配置檔案:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵

流控規則中的來源指定

  • 修改處理器:修改 06-consumer-sentinel-reqsource-8080 工程中的 DepartController:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 啟動提供者啟動 04-provider-nacos-8081 工程
  • dashbaord 指定來源:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • dashboard 指定同名規則:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 以上規則的意思是,對于 serviceA 來源的請求,其 QPS 的門檻值為 2;對于 serviceB 來源的請求,其 QPS 的門檻值為 3;而其它來源的請求,其 QPS 的門檻值為 10。但它們都是用于限制資源名稱為 reqsourceRule 的資源的。
  • 測試:并發通路 http://localhost:8080/consumer/depart/get/1?source=serviceA、http://localhost:8080/consumer/depart/get/1?source=serviceB、http://localhost:8080/consumer/depart/get/1?source=other。驗證下流控效果。

動态設定黑白名單

  • 流控規則中,一條規則僅可指定一個來源,若要指定多個來源,則需要定義多條同名規則,比較麻煩。可以通過黑白名單來一次性指定多個來源。
  • dashboard 定義 QPS 流控規則:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • dashboard 定義授權規則:
JavaEE 企業級分布式進階架構師(二十)微服務架構 SpringCloudAlibaba (2.2 版)(4)Sentinel流量防衛兵
  • 測試:通路 http://localhost:8080/consumer/depart/get/1?source=serviceA、http://localhost:8080/consumer/depart/get/1?source=serviceB 是可以的,并且進行了流控 QPS = 2,但是其他的通路都直接降級了。

代碼設定黑白名單

@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class Consumer068080 {
    public static void main(String[] args) {
        SpringApplication.run(Consumer068080.class, args);
        initRule();
    }

    private static void initRule() {
        List<AuthorityRule> rules = new ArrayList<>();
        rules.add(reqSourceRule());
        AuthorityRuleManager.loadRules(rules);
    }

    private static AuthorityRule reqSourceRule() {
        AuthorityRule rule = new AuthorityRule();
        rule.setResource("reqSourceRule");
        rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
        rule.setLimitApp("serviceA,serviceB");
        return rule;
    }
}
           

繼續閱讀