天天看點

SpringCloud Sentinel 學習筆記

Sentinel 教程學習筆記

目錄

    • 學習進度
    • 1. Sentinel 介紹
      • 1.1 Sentinel 的組成
      • 1.2. Sentinel 的特征
      • 1.3. 相關概念
    • 2. Sentinel 初體驗
      • 2.1 限流規則體驗
        • 2.1.1 修改pom.xml添加依賴
        • 2.1.2 定義一個Controle來測試CentinelAPI
        • 2.1.3 測試限流效果
      • 2.2 熔斷降級體驗
        • 2.2.1 添加依賴;
        • 2.2.2 在controller中定義資源
        • 2.2.3 在controller定義熔斷規則
    • 3. Sentinel 控制台
      • 3.1 本地控制台搭建
      • 3.2 用戶端接入控制台
      • 3.3 Sentinel 定義資源的方式
        • 3.3.1 抛出異常的方式
        • 3.3.2 傳回布爾值方式定義資源
        • 3.3.3 異步調用支援
        • 3.3.4 注解方式定義資源
    • 4. Sentinel進階
      • 4.1 Sentinel 和 SpringCloud整合
      • 4.2 Sentinel對Fegin的支援
      • 4.3 Sentinel 對 Spring Cloud Gateway 的支援
      • 4.4 系統自适應保護
      • 4.5 Sentinel授權控制

P19

核心庫(Java 用戶端): 不依賴任何架構 / 庫,能夠運作于所有 Java 運作時環境,同時對 Dubbo / Spring Cloud 等架構也有較好的支援;

控制台(Dashboard): 基于 Spring Boot 開發,打包後可以直接運作,不需要額外的 Tomcat 等應用容器;

豐富的應用場景: Sentinel 承接了阿裡巴巴近 10 年的雙十一大促流量的核心場景,例如秒殺(即突發流量控制在系統容量可以承受的範圍)、消息削峰填谷(對于突然到來的大量請求,您可以配置流控規則,以穩定的速度逐漸處理這些請求,進而避免流量突刺造成系統負載過高)、叢集流量控制、實時熔斷下遊不可用應用等;

完備的實時監控: Sentinel 同時提供實時的監控功能。您可以在控制台中看到接入應用的單台機器秒級資料,甚至 500 台以下規模的叢集的彙總運作情況;

廣泛的開源生态: Sentinel 提供開箱即用的與其它開源架構 / 庫的整合子產品,例如與 Spring Cloud、Dubbo、gRPC 的整合。您隻需要引入相應的依賴并進行簡單的配置即可快速地接入 Sentinel;

完善的 SPI 擴充點: Sentinel 提供簡單易用、完善的 SPI 擴充接口。您可以通過實作擴充接口來快速地定制邏輯。例如定制規則管理、适配動态資料源等;

資源 資源是Sentinel的關鍵概念,它可以是Java應用程式中的任何内容,比如程式提供的服務,或者是一段代碼。隻要通過Sentinel API定義的代碼,就是資源,能夠被Sentinel保護起來。大部分情況下,可以使用方法簽名,URL,甚至服務名稱作為資源名來表示資源。

規則 規則是指圍繞着資源的實時狀态設定的規則,它可以包括流量控制規則、熔斷降級規則以及保護規則。所有規則可以動态實時調整。

流量控制:根據系統的處理能力對流量進行控制,處理不了的請求直接丢棄;

熔斷降級:如果某個資源不穩定,最終會導緻請求發生堆積,在微服務系統中進而導緻級聯錯誤,熔斷機制可以應對這種問題,對資源進行控制,讓請求快速失敗,避免影響其他的資源而産生級聯故障;當資源被降級後,在接下來的降級時間視窗内,對該資源的調用都會自動熔斷(預設行為是抛出DegradeException);

使用SpringBoot工程,通過Sentinel的API來體驗一把資源的限流保護;下面的代碼是通過在代碼中定義限流規則的,在介紹到Sentinel控制台後,我們就可以在控制裡動态的設定限流規則;

<!--添加Sentinel依賴-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>1.7.2</version>
        </dependency>
           

關鍵點

  • SphU.entry 來定義限流入口,并定義資源名稱;
  • 使用@PostConstruct注解在構造方法執行後,添加自定義的限流規則;
  • BlockException 限流規則被觸發後抛出的異常;
package com.linwei.sentinel.control;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

/**
 * @author: linwei
 * @date: 2021/7/15 22:41
 * @Description:
 */

@RestController
public class TestContorl {

    @GetMapping("/hello")
    public String hello(){
        try (Entry entry = SphU.entry("Hello")){ //限流入口
            return "Hello Sentinel!";  //這裡就是被保護的資源
        }catch (BlockException ex){
            ex.printStackTrace();
            return "系統繁忙,稍後重試!";  //限流規則觸發後的操作
        }

    }

    // 定義限流規則
    // @PostConstruct 該注解的作用是在目前類的構造原函數執行之後執行的方法
    @PostConstruct
    public void initFlowRules(){
        //1. 建立存放限流規則的集合
        List<FlowRule> rules = new ArrayList<>();
        //2. 建立限流規則
        FlowRule rule1 = new FlowRule();
        // 定義資源
        rule1.setResource("Hello");
        // 定義限流規則類型
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 設定QPS的限流值
        rule1.setCount(2);

        //3. 将限流規則存放到集合中
        rules.add(rule1);
        //4. 加載限流規則
        FlowRuleManager.loadRules(rules);

    }
}

           

我們在代碼裡設定的限流規則是每秒處理兩個QPS,是以當我們在浏覽器頻繁重新整理請求

/hello

時,就會觸發限流規則;

浏覽器顯示如下:

Hello Sentinel!
           
系統繁忙,稍後重試!
           

熔斷降級會在調用鍊路中,某個資源出現不穩定狀态時(例如調用逾時或異常比例升高),對這個資源的調用進行限制,讓請求快速失敗,避免影響到其他的資源導緻級聯錯誤。當資源被降級後,在接下來的降級時間視窗内,對該資源的調用都會自動熔斷(預設行為是抛出DegradeException);

熔斷降級的規則設定有兩種方式:

  • 本地代碼設定;
  • 在Sentinel控制台動态設定;

以下以本地代碼為例進行示範:

這一步跟上面的2.1.1是一樣的,已經添加過依賴,這一步就可以跳過;

下面是使用了注解的方式定義資源;

@RestController
public class TestController {

    // Sentinel 注解方式定義資源;  限流控制
    @GetMapping("ann-test")
    @SentinelResource(value="sentinel-ann",blockHandler = "exceptionHandler")
    public String annotionTest(){
        return "hello sentinel annotation";
    }

    // blockHandler函數
    public String exceptionHandler(BlockException ex){
        ex.printStackTrace();
        return "系統繁忙,請稍後";
    }


    // Sentinel 注解方式定義資源  熔斷控制
    @SentinelResource(value = "sentinel-deg",fallback = "exceptionHandler2")
    @RequestMapping("/deg-test")
    public String degradeTest(){
        return "hello sentinel degrade test!";
    }

    //降級方法
    public String exceptionHandler2(){
        return "觸發熔斷降級,系統繁忙,請稍後";
    }

}
           

我們繼續在上面的代碼裡,用代碼的方式進行定義熔斷規則,使用sentinel控制台後,這個步驟就不用要了,隻需要上面定義好資源後,在控制台去定義規則即可;

// 定義熔斷規則
    // @PostConstruct 該注解的作用是在目前類的構造原函數執行之後執行的方法
    @PostConstruct
    public void initFlowRules(){
        //1. 建立存放限流規則的集合
        List<DegradeRule> rules = new ArrayList<>();
        //2. 建立限流規則
        DegradeRule rule = new DegradeRule();
        // 定義資源
        rule.setResource("sentinel-deg");
        // 定義限流規則類型:熔斷降級(秒級RT)類型
        rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
        // 設定門檻值
        rule.setCount(0.01);
        // 降級的時間視窗,機關為s
		rule.setTimeWindow(10);
        //3. 将限流規則存放到集合中
        rules.add(rule);
        //4. 加載限流規則
        DegradeRuleManager.loadRules(rules);

    }
           

在浏覽器方式

http://localhost:8080/deg-test

,慢速重新整理可以正常傳回,快速重新整理幾次後,出現

觸發熔斷降級,系統繁忙,請稍後

,并且之後再次重新整理,即使慢速重新整理還是提示繁忙,等待10秒後,又正常顯示了,說明對資源的熔斷降級生效了。

  1. 下載下傳jar包;
  • 方式1:從 release 頁面 下載下傳最新版本的控制台 jar 包(sentinel-dashboard-1.8.2.jar);
  • 方式2:也可以從最新版本的源碼自行建構 Sentinel 控制台;
  1. 啟動jar包
java -Dserver.port=9000 -jar sentinel-dashboard-1.8.2.jar
           
  1. 通路Sentinel控制台

浏覽器打開: http://localhost:9000/ 登陸賬号密碼預設均為sentinel;

(參考官網,普通Springboot項目接入Sentinel控制台)

預設情況下Sentinel 會在用戶端首次調用的時候進行初始化,開始向控制台發送心跳包。也可以配置

sentinel.eager=true ,取消Sentinel控制台懶加載。

打開浏覽器即可展示Sentinel的管理控制台。

  1. 在用戶端pom.xml引入 Transport 子產品來與 Sentinel 控制台進行通信
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-transport-simple-http</artifactId>
    <version>1.8.2</version>
</dependency>
           
  1. 啟動時加入 JVM 參數指定sentinel控制台的Ip和端口,并指定目前用戶端的名稱
-Dcsp.sentinel.dashboard.server=localhost:9000 -Dproject.name=sentinel-demo
           

完成以上步驟後即可在 Sentinel 控制台上看到對應的應用,機器清單頁面可以看到對應的機器,如果看不到,就通路以下用戶端,因為sentinel預設是懶加載;

  1. 将代碼裡的限流規則注釋掉,在sentinel控制台添加限流規則
@RestController
public class TestContorl {

    @GetMapping("/hello")
    public String hello(){
        Entry entry = null;
        try { //限流入口
            entry = SphU.entry("Hello");
            return "Hello Sentinel!";  //這裡就是被保護的資源
        }catch (BlockException ex){
            ex.printStackTrace();
            return "系統繁忙,稍後重試!";  //限流規則觸發後的操作
        } finally {
            if (entry != null) {
                entry.exit();
            }

            ContextUtil.exit();
        }
    }

    // 定義限流規則
    // @PostConstruct 該注解的作用是在目前類的構造原函數執行之後執行的方法
    /*@PostConstruct
    public void initFlowRules(){
        //1. 建立存放限流規則的集合
        List<FlowRule> rules = new ArrayList<>();
        //2. 建立限流規則
        FlowRule rule1 = new FlowRule();
        // 定義資源
        rule1.setResource("Hello");
        // 定義限流規則類型
        rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
        // 設定QPS的限流值
        rule1.setCount(2);

        //3. 将限流規則存放到集合中
        rules.add(rule1);
        //4. 加載限流規則
        FlowRuleManager.loadRules(rules);

    }*/
    
}
           
SpringCloud Sentinel 學習筆記
SpringCloud Sentinel 學習筆記

Sentinel 定義資源的方式有以下幾種:

  • 抛出異常的方式
  • 傳回布爾值方式
  • 異步調用支援
  • 注解方式
  • 主流架構的預設适配

Sentinel中SphU包含了try-catch風格的API,用這種方式,當資源發生了限流之後會抛出BlockException異常。這個時候可以捕獲異常,進行限流之後的邏輯處理,例如:

把需要控制流量的代碼用 Sentinel API SphU.entry("HelloWorld") 和 entry.exit() 包圍起來即可

try (Entry entry = SphU.entry("Hello")){ //限流入口,被保護的資源
        return "Hello Sentinel!";  //這裡就是被保護的資源
    }catch (BlockException ex){
        ex.printStackTrace();
         return "系統繁忙,稍後重試!";  //限流規則觸發後的操作
    } 
           

Sentinel中SphO的API提供if-else風格的API,用這種方式,當資源發生了限流之後會傳回false,這個時候可以根據傳回值,進行限流之後的邏輯處理;

SphO.entry(xxx)需要與SphO.exit()成對出現,否則會導緻調用鍊記錄異常,抛出ErrorEntryFreeException異常

定義一個測試的controller,然後在Sentinel控制添加對應資源的限流規則,檢視限流時候生效;正常情況下,限流觸發後會執行else裡面的邏輯;

@RequestMapping("boolean-test")
    public String booleanTest(){
        if(SphO.entry("sentinel-boolean")){ //限流入口,被保護的資源名稱
            try {
                // 被保護的資源...
                return "通路成功!";
            }finally {
                // SphO.entry(xxx)需要與SphO.exit()成對出現,否則會導緻調用鍊記錄異常,抛出ErrorEntryFreeException異常
                SphO.exit(); //限流出口
            }
        }else{
            // 限流規則被觸發後的邏輯處理
            return "限流規則觸發,通路失敗!";
        }
    }
           

Sentinel支援異步調用鍊路,在異步調用中,需要通過SphU.asyncEntry(XXX)定義資源,并需要在異步回調函數中調用exit方法;

  1. 在本地引用的引導類中添加注解@EnableAsync, 表示springboot項目開啟異步調用支援;
@EnableAsync
@SpringBootApplication
public class SentinelDemoApplication {

    public static void main(String[] args) {
        SpringApplication.run(SentinelDemoApplication.class, args);
    }

}
           
  1. 建立SyncService編寫異步調用方法
@Service
public class MyAsyncService {

    // @Async 注解表示該方法為異步調用方法
    @Async
    public void hello(){
        System.out.println("--->異步方法開始");
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("--->異步方法結束");
    }
}
           
  1. 在controller中調用異步方法,實作異步調用限流控制
// Sentinel 對異步調用的支援
    @Autowired
    private MyAsyncService asyncService;
    @GetMapping("async")
    public void asyncTest(){
        // 1. 進行限流控制
        AsyncEntry asyncEntry = null;
        try {
            asyncEntry = SphU.asyncEntry("sentinel-async"); // 定義限流資源名稱(限流入口)
            asyncService.hello(); // 異步方法調用
            System.out.println("----continue..."); // 異步方法調用後該語句繼續執行
        } catch (BlockException e) {
            System.out.println("---> 系統忙,請稍後!");  // 被限流或降級觸發後的邏輯處理
        }finally {
            if(asyncEntry != null){
                asyncEntry.exit();  // 限流出口
            }
        }

    }
           

Sentinel支援通過注解 @SentinelResource 注解方式定義資源并配置 blockHandler 函數來進行限流之後的處理。

步驟:

  1. 引入相關依賴;

    因為Sentinel中使用AspectJ的擴充用于自定義資源、處理BlockException等,是以需要在項目中引入sentinel-annotation-aspectj依賴;

<dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>1.8.2</version>
    </dependency>
           
  1. 建立AspectJ的配置類
@Configuration
public class SentinelAspectConfig {
    
    @Bean
    public SentinelResourceAspect sentinelResourceAspect(){
        return new SentinelResourceAspect();
    }
}
           
  1. 建立testController,進行測試驗證;
// Sentinel 注解方式定義資源
    @GetMapping("ann-test")
    @SentinelResource(value="sentinel-ann",blockHandler = "exceptionHandler")
    public String annationTest(){
        return "hello sentinel annotation";
    }

    // blockHandler函數
    public String exceptionHandler(BlockException ex){
        ex.printStackTrace();
        return "系統繁忙,請稍後";
    }
           

SrpingCloudAlibaba 是阿裡巴巴提供,緻力于提供微服務開發的一站式解決方案。Spring Cloud Alibaba 預設為Sentinel 整合了Servlet、RestTemplate、FeignClient和Spring WebFlux。 Sentinel在Spring Cloud生态中,不僅不全了Hystrix在Servlet和RestTemplate這一塊的空白,而且還相容了Hystrix在FeignClent中限流降級的用法,并且支援運作時靈活配置和調整連休降級規則;

具體步驟

  1. 建立SpringBoot項目,在項目中引入spring-cloud-starter-alibaba-sentinel依賴
<dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-alibaba-sentinel</artifactId>
            <version>2.1.0.RELEASE</version>
        </dependency>
           
  1. 建立Controller用來測試
@RestController
public class TestController {

    // Sentinel 注解方式定義資源
    @GetMapping("ann-tet")
    @SentinelResource(value="sentinel-ann",blockHandler = "exceptionHandler")
    public String annotionTest(){
        return "hello sentinel annotation";
    }

    // blockHandler函數
    public String exceptionHandler(BlockException ex){
        ex.printStackTrace();
        return "系統繁忙,請稍後";
    }

}
           
  1. application.properties

    配置檔案中添加

    Sentinel

    控制台配置
# 應用名稱
spring.application.name=springcloudsentinel-demo
# 應用服務 WEB 通路端口
server.port=8081
# 設定Sentinel控制台的主機位址和端口
spring.cloud.sentinel.transport.dashboard=localhost:9000
           

Sentinel

适配了

Feign

元件。如果想要使用,除了引用

spring-cloud-starter-alibaba-sentinel

的依賴,還需要兩個步驟:

  • 配置打開

    Sentinel對Feign

    的支援:

    feign.sentinel.enable=true

  • 加入

    spring-cloud-starter-openfeign

    依賴使

    Sentinel starter

    自動化配置類生效
  1. 引入Spring Cloud Alibaba Sentinel依賴
    <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
            </dependency>
    
               
  2. 在application.properties配置檔案中開啟Sentinel對Feign的支援
    #設定Sentinel控制台的主機位址和端口
    spring.cloud.sentinel.transport.dashboard=localhost:9000
    #打開Sentinel對Feign的支援
    feign.sentinel.enabled=true
               
  3. 建立FallbackService,作為限流降級回調類,并在FeignAgent進行流控降級回調配置
    // 限流或降級的回調類
    @Component
    public class FallbackService implements FeignAgent {
        //限流和降級的處理
        @Override
        public String hello() {
            return "系統繁忙,請稍候";
        }
    }
    
               

定義feign用戶端接口

// feign 用戶端
@FeignClient(value = "sentinel-feign-provider", fallback = FallbackService.class)
public interface FeignAgent {

    @GetMapping("/api/v1/hello")
    String hello();
}

           

服務消費者的測試controller

@RestController
public class TestController{
	@Autowired
	private FeignAgent feignAgent;
	
	@GetMapping("/hello")
	public String hello(){
		return feignAgent.hello();
	}
}
           
  1. 設定限流規則測試

    Sentinel與Feign整合時,流控規則的編寫形式為:http請求方式:協定://服務名/請求路徑和參數(請求路徑和參數為@FeignClient中的請求路徑,也就是本服務調用下遊服務的URL)

    例如:

    GET:http://sentinel-feign-provider/api/v1/hello

    如果快速重新整理http://localhost:8090/api/v1/consumer/hello,會出現系統繁忙,請稍候
  2. 請求位址中包含參數的資源名配置

    如果是多個@RequestParam,資源名不需要帶上@RequestParam, 如果請求路徑中包含@PathVariable,案例如下:

    sentinel控制台資源名定義為:

    GET:http://sentinel-feign-provider/api/v1/hello/{hello}

    @FeignClient(value = "sentinel-feign-provider", fallback = FallbackService.class)
    public interface FeignAgent {
    
        @GetMapping("/api/v1/hello/{hello}")
        String hello(@PathVariable(value = "hello") String hello);
    }
               

Sentinel整合Spring Cloud gateway

  1. 在gateway的

    pom.xml

    中引入依賴;
    <!-- Spring Cloud Alibaba Sentinel 依賴 -->
    		<dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
                <version>2.2.3.RELEASE</version>
            </dependency>
           <!-- Sentinel支援Spring Cloud Gateway 的依賴 -->
    		<dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId>
                <version>2.2.3.RELEASE</version>
            </dependency>
               
  2. 建立

    GatewayConfiguration

    配置類,配置流控降級回調操作;
    @Component
    public class GatewayConfiguration {
         @PostConstruct
        public void doInit(){
             //設定限流或降級的回調函數
             GatewayCallbackManager.setBlockHandler(new BlockRequestHandler() {
                 @Override
                 public Mono<ServerResponse> handleRequest(ServerWebExchange serverWebExchange, java.lang.Throwable throwable) {
                    return ServerResponse.status(200).syncBody("系統繁忙請稍後");
                 }
             });
         }
    }
    
               
  3. application.yaml

    中配置

    sentinel

    控制台通路位址;
    spring:
      cloud:
        sentinel:
          transport:
            port: 8718
            dashboard: 127.0.0.1:8080
               
  4. 運作測試;

sentinel

在适配

spring cloud gateway

時提供了兩種配置規則:

  • route次元

    :即在spring配置檔案配置的路由條數,資源名為對應的

    routeId

    ;
  • 自定義API次元:使用者可以利用

    Sentinel

    提供的API來自定義一些自定義分組;

在sentinel控制台中,添加網關限流規則的界面跟普通限流規則的界面不太相同,如下圖:

API類型選擇Route ID , 就是輸入gateway中路徑的routeid; 如果選擇的是API分組,就需要先在Sentinel控制台網關目錄下的菜單“API管理” 裡定義API分組,然後在添加留白規則的這個界面上選擇API分組;

SpringCloud Sentinel 學習筆記

Sentinel系統自适應限流是從應用的整體次元進行入口流量控制,結合應用的Load,CPU使用率,總體平均RT,入口QPS和并發線程數等幾個次元的監控名額,通過自适應的流控政策,來讓系統入口流量和系統的負載達到一個平衡,讓系統盡可能保持最大吞吐量的同時保證系統整體的穩定性;

  • 本地代碼方式;
  • Sentinel控制台動态配置;
@RestController
public class SysController {

    // 這裡定義的資源就沒有定義資源的名稱和處理函數了,因為系統自适應的次元是整個應用,sentinel也會有預設的限流和降級的處理函數;
    // EntryType.IN 表示這是一個入口資源,自适應保護也隻對這樣的入口資源生效;
    @SentinelResource(entryType = EntryType.IN)
    @RequestMapping("/sys")
    public String sysHello(){
        return "hello sentinel!";
    }

    // 代碼方式定義規則
    @PostConstruct
    private void initSystemRule(){
        //1. 建立存放限流規則的集合
        List<SystemRule> rules = new ArrayList<>();
        //2. 建立自适應規則
        SystemRule rule = new SystemRule();
        // 設定入口QPS
        rule.setQps(2);
        //3. 将限流規則存放到集合中
        rules.add(rule);
        //4. 加載限流規則
        SystemRuleManager.loadRules(rules);
    }

}
           

繼續閱讀