Sentinel 基本认识

Sentinel 是一种面向分布式微服务架构的轻量级高可用流量控制组件,由阿里巴巴中间件团队开发的开源项目。Sentinel 主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。详细参考 官网详解 Sentinel 主要由以下两个部分组成:
  • Sentinel 核心库:Sentinel 的核心库不依赖任何框架或库,能够运行于 Java 8 及以上的版本的运行时环境中,同时对 Spring Cloud、Dubbo 等微服务框架提供了很好的支持。
  • Sentinel 控制台(Dashboard):Sentinel 提供的一个轻量级的开源控制台,它为用户提供了机器自发现、簇点链路自发现、监控、规则配置等功能。
Sentinel 核心库不依赖 Sentinel Dashboard,但两者结合使用可以有效的提高效率,让 Sentinel 发挥它最大的作用。
Sentinel 的基本概念有两个,资源 规则
基本概念 描述
资源 资源是 Sentinel 的关键概念。它可以是 Java 应用程序中的任何内容,例如由应用程序提供的服务或者是服务里的方法,甚至可以是一段代码。 我们可以通过 Sentinel 提供的 API 来定义一个资源,使其能够被 Sentinel 保护起来。通常情况下,我们可以使用方法名、URL 甚至是服务名来作为资源名来描述某个资源。
规则 围绕资源而设定的规则。Sentinel 支持流量控制、熔断降级、系统保护、来源访问控制和热点参数等多种规则,所有这些规则都可以动态实时调整。
Sentinel 控制台 Sentinel 提供了一个轻量级的开源控制台 Sentinel Dashboard,它提供了机器发现与健康情况管理、监控(单机和集群)、规则管理与推送等多种功能。
Sentinel 控制台提供的功能如下:
  • 查看机器列表以及健康情况:Sentinel 控制台能够收集 Sentinel 客户端发送的心跳包,判断机器是否在线。
  • 监控(单机和集群聚合):Sentinel 控制台通过 Sentinel 客户端暴露的监控 API,可以实现秒级的实时监控。
  • 规则管理和推送:通过 Sentinel 控制台,我们还能够针对资源定义和推送规则。
  • 鉴权:从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel。

安装 Sentinel Dashboard

  1. 下载Sentinel Dashboard <font style="color:rgb(68, 68, 68);">jar</font> 地址入口Releases · alibaba/Sentinel

Spring Cloud Alibaba Sentinel - 图1

  1. 打开命令行窗口,跳转 Sentinel Dashboard jar 包所在的目录,执行以下命令,启动 Sentinel Dashboard
  1. java -jar sentinel-dashboard-1.8.5.jar

Spring Cloud Alibaba Sentinel - 图2

  1. 访问 http://localhost:8080/ 默认账号/密码:sentinel/sentinel

Spring Cloud Alibaba Sentinel - 图3

Spring Cloud Alibaba Sentinel - 图4

Sentinel 使用步骤方法

  1. 新建 Module spring-cloud-alibaba-sentinel-8501

Spring Cloud Alibaba Sentinel - 图5

  1. 导入 Sentinel依赖
  1. <?xml version="1.0" encoding="UTF-8"?>
  2. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  4. <modelVersion>4.0.0</modelVersion>
  5. <!--父工程-->
  6. <parent>
  7. <groupId>com.chen</groupId>
  8. <artifactId>spring-cloud-alibaba-demo</artifactId>
  9. <version>1.0-SNAPSHOT</version>
  10. </parent>
  11. <groupId>com.chen</groupId>
  12. <artifactId>spring-cloud-alibaba-sentinel-8501</artifactId>
  13. <version>0.0.1-SNAPSHOT</version>
  14. <name>spring-cloud-alibaba-sentinel-8501</name>
  15. <description>spring-cloud-alibaba-sentinel-8501</description>
  16. <properties>
  17. <java.version>1.8</java.version>
  18. </properties>
  19. <dependencies>
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-web</artifactId>
  23. </dependency>
  24. <dependency>
  25. <groupId>org.springframework.boot</groupId>
  26. <artifactId>spring-boot-devtools</artifactId>
  27. <scope>runtime</scope>
  28. <optional>true</optional>
  29. </dependency>
  30. <dependency>
  31. <groupId>org.springframework.boot</groupId>
  32. <artifactId>spring-boot-starter-test</artifactId>
  33. <scope>test</scope>
  34. </dependency>
  35. <!--SpringCloud ailibaba nacos -->
  36. <dependency>
  37. <groupId>com.alibaba.cloud</groupId>
  38. <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
  39. </dependency>
  40. <!--SpringCloud ailibaba sentinel -->
  41. <dependency>
  42. <groupId>com.alibaba.cloud</groupId>
  43. <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
  44. </dependency>
  45. <dependency>
  46. <groupId>cn.hutool</groupId>
  47. <artifactId>hutool-all</artifactId>
  48. <version>5.3.8</version>
  49. </dependency>
  50. </dependencies>
  51. <build>
  52. <plugins>
  53. <plugin>
  54. <groupId>org.springframework.boot</groupId>
  55. <artifactId>spring-boot-maven-plugin</artifactId>
  56. </plugin>
  57. </plugins>
  58. </build>
  59. </project>
  1. yaml 配置
server:
  port: 8501

spring:
  application:
    name: chen-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: 127.0.0.1:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8917

management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. 主启动类添加 <font style="color:#9e880d;">@EnableDiscoveryClient</font>
package com.chen.springcloudalibabasentinel8501;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;

@SpringBootApplication
@EnableDiscoveryClient
public class SpringCloudAlibabaSentinel8501Application {

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

}
  1. 业务类
package com.chen.springcloudalibabasentinel8501.controller;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class FlowLimitController {

    @Value("${server.port}")
    private String serverPort;


    @GetMapping("/testA")
    public String testA() {
        return "serverPort:[" + serverPort + "],testA……";
    }

    @GetMapping("/testB")
    public String testB() {
        return "serverPort:[" + serverPort + "],testB……";
    }
}
  1. Sentinel采用懒加载机制。所以请求 http://localhost:8501/testB后,Sentinel 控制台 首页 下方新增了一个 chen-sentinel-service 的菜单,而这正是 spring-cloud-alibaba-sentinel-8501 的服务名(spring.application.name),说明 Sentinel 已经监控到这个服务,如下图。

Spring Cloud Alibaba Sentinel - 图6

实时监控

可以实时监测我们的服务请求次数,我们多次刷新请求页面,这里都可以记录下来

Spring Cloud Alibaba Sentinel - 图7

定义资源

资源是 Sentinel 中的核心概念之一。在项目开发时,我们只需要考虑这个服务、方法或代码是否需要保护,如果需要保护,就可以将它定义为一个资源。Sentinel 为我们提供了多种定义资源的方式:
  • 适配主流框架自动定义资源
  • 通过 SphU 手动定义资源
  • 通过 SphO 手动定义资源
  • 注解方式定义资源

适配主流框架自动定义资源

Sentinel 对大部分的主流框架都进行了适配,我们只要引入相关的适配模块(<font style="color:rgb(68, 68, 68);">spring-cloud-starter-alibaba-sentinel</font>),Snetinel 就会自动将项目中的服务(包括调用端和服务端)定义为资源,资源名就是服务的请求路径。此时,我们只要再定义一些规则,这些资源就可以享受到 Sentinel 的保护。 我们可以在 Sentinel 控制台的“簇点链路”中,直接查看被 Sentinel 监控的资源,如下图:

Spring Cloud Alibaba Sentinel - 图8

通过 SphU 手动定义资源

Sentinel 提供了一个名为 SphU 的类,它包含的 try-catch 风格的 API ,可以帮助我们手动定义资源。使用步骤如下:

  1. 在SentinelFlowLimitController 中新增一个 <font style="color:#00627a;">testCbySphU</font>()方法定义一个名为 <font style="color:#00627a;">testCbySphU</font>的资源,代码如下
@GetMapping("/testC")
public String testC() {
    return testCbySphU();
}

/**
 * 通过 SphU 手动定义资源
 */
public String testCbySphU() {
    Entry entry = null;
    try {
        entry = SphU.entry("testAbySphU");
        String str = "testCbySphU端口[" + serverPort + "]请求成功";
        System.out.println(str);
        return str;
    } catch (BlockException e) {
        String str = "testCbySphU端口[" + serverPort + "]请求被限流";
        System.out.println(str);
        return str;
    } finally {
        if (entry != null) {
            entry.exit();
        }
    }
}
  1. 重启项目,浏览器访问 http://localhost:8501/testC

Spring Cloud Alibaba Sentinel - 图9

Spring Cloud Alibaba Sentinel - 图10

通过 SphO 手动定义资源

Sentinel 还提供了一个名为 SphO 的类,它包含了 if-else 风格的 API,能帮助我们手动定义资源。通过这种方式定义的资源,发生了限流之后会返回 false,此时我们可以根据返回值,进行限流之后的逻辑处理。
  1. 在SentinelFlowLimitController 中新增一个 <font style="color:#00627a;">testDbySphO</font>()方法定义一个名为 testDbySphO的资源,代码如下
@GetMapping("/testD")
public String testD() {
    return testDbySphO();
}

/**
 * 通过 SphO 手动定义资源
 */
public String testDbySphO() {
    if (SphO.entry("testDbySphO")) {
        // 务必保证finally会被执行
        try {
            String str = "testDbySphU端口[" + serverPort + "]请求成功";
            return str;
        } finally {
            SphO.exit();
        }
    } else {
        // 资源访问阻止,被限流或被降级
        //流控逻辑处理 - 开始
        String str = "testDbySphU端口[" + serverPort + "]请求被限流";
        return str;
        //流控逻辑处理 - 结束
    }
}
  1. 重启项目,浏览器访问 http://localhost:8501/testD

Spring Cloud Alibaba Sentinel - 图11

Spring Cloud Alibaba Sentinel - 图12

注解方式定义资源(推荐)

除了以上两种方式外,我们还可以通过 Sentinel 提供的 @SentinelResource 注解定义资源,步骤如下:
  1. 在SentinelFlowLimitController 中新增一个 <font style="color:#00627a;">testEbyAnnotation</font>()方法定义一个名为 testEbyAnnotation的资源,代码如下
@GetMapping("/testE")
@SentinelResource("testEbyAnnotation")
public String testE() {
    return testEbyAnnotation();
}

public String testEbyAnnotation(){
    String str = "testEbySphU端口[" + serverPort + "]请求成功";
    return str;
}
  1. 重启项目,浏览器访问 http://localhost:8501/testE

Spring Cloud Alibaba Sentinel - 图13

Spring Cloud Alibaba Sentinel - 图14

Sentinel 流量控制

Spring Cloud Alibaba Sentinel - 图15

资源名:唯一名称,默认请求路径 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源) 阈值类型/单机阈值:
  • QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流。线程数:当调用该api的线程数达到阈值的时候,进行限流
是否集群:不需要集群 流控模式:
  • 直接:api达到限流条件时,直接限流
  • 关联:当关联的资源达到阈值时,就限流自己
  • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】
流控效果:
  • 快速失败:直接失败,抛异常
  • Warm Up:根据codeFactor(冷加载因子,默认3)的值,从阈值/codeFactor,经过预热时长,才达到设 置的QPS阈值
  • 排队等待:匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效

流量控制简单使用

任何系统处理请求的能力都是有限的,但任意时间内到达系统的请求量往往是随机且不可控的,如果在某一个瞬时时刻请求量急剧增,那么系统就很有可能被瞬时的流量高峰冲垮。为了避免此类情况发生,我们都需要根据系统的处理能力对请求流量进行控制,这就是我们常说的 流量控制,简称 流控 Sentinel 作为一种轻量级高可用流量控制组件,流量控制是它最主要的工作之一。 我们可以针对资源定义流控规则,Sentinel 会根据这些规则对流量相关的各项指标进行监控。指标当达到或超过流控规则规定的阈值时,Sentinel 会对请求的流量进行限制(即限流),以避免系统被瞬时的流量高峰冲垮,保障系统的高可用性。 一条流量规则主要由下表中的属性组成,我们可以通过组合这些属性来实现不同的限流效果。
属性 说明 默认值
资源名(resource 流控规则的作用对象。
阈值(count 流控的阈值。
阈值类型(grade 流控阈值的类型,包括 QPS 或并发线程数。 QPS
针对来源(limitApp 流控针对的调用来源。 default,表示不区分调用来源
流控模式(strategy 调用关系限流策略,包括直接、链路和关联。 直接
流控效果(controlBehavior 流控效果(直接拒绝、Warm Up、匀速排队),不支持按调用关系限流。 直接拒绝
QPS 表示并发请求数,即每秒钟最多通过的请求数。
同一个资源可以创建多条流控规则,Sentinel 会遍历这些规则,直到有规则触发限流或者所有规则遍历完毕为止。
Sentinel 触发限流时,资源会抛出 BlockException 异常,此时我们可以捕捉 BlockException 来自定义被限流之后的处理逻辑。

Sentinel 控制台定义流控规则

  1. SentinelFlowLimitController 中新增一个名为 testF 的服务方法如下:
@GetMapping("/testF")
public String testF() {
    return "serverPort:[" + serverPort + "],testF……";
}
  1. 重启服务,访问 http://localhost:8501/testF

Spring Cloud Alibaba Sentinel - 图16

  1. 到控制台对资源设置规则

Spring Cloud Alibaba Sentinel - 图17

点击<font style="color:rgb(68, 68, 68);">/testF</font>右侧的 +流控 按钮,在弹出的“新增流控规则”窗口中定义流控规则

Spring Cloud Alibaba Sentinel - 图18

  1. 快速连续(频率大于每秒钟 2 次)访问 http://localhost:8501/testF,结果如下
正常:Spring Cloud Alibaba Sentinel - 图19 异常:Spring Cloud Alibaba Sentinel - 图20 :::info 若页面中出现以上信息,则说明该服务已被限流,但这种提示是 Sentinel 系统自动生成的,用户体验不好,实际开发中我们都会自定义相应的异常返回。 ::: 5. 在服务代码中使用 @SentinelResource 注解定义资源名称,并在 blockHandler 属性指定一个限流函数,自定义服务限流信息,代码如下。 java @GetMapping("/testF") @SentinelResource(value = "testF-resource",blockHandler = "blockHandlerTestF") public String testF() { return "serverPort:[" + serverPort + "],testF……"; } public String blockHandlerTestF(BlockException exception){ String str = Thread.currentThread().getName() + "端口[" + serverPort + "]请求被限流,请稍后重试"; return str; } 在以上代码中,我们通过 @SentinelResource 注解的 blockHandler 属性指定了一个 blockHandler 函数,进行限流之后的后续处理。
使用 @SentinelResource 注解的 blockHandler 属性时,需要注意以下事项:
  • blockHandler 函数访问范围需要是 public;
  • 返回类型需要与原方法相匹配;
  • 参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException;
  • blockHandler 函数默认需要和原方法在同一个类中,若希望使用其他类的函数,则可以指定 blockHandler 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析。
  • 请务必添加 blockHandler 属性来指定自定义的限流处理方法,若不指定,则会跳转到错误页(用户体验不好)。
  1. 在Sentinel 控制台主页,点击 sentinel-sevice 下的 簇点链路,点击资源<font style="color:rgb(68, 68, 68);">testD-resource</font>右侧的 +流控 按钮,并在弹出的“新增流控规则”窗口中为这个资源定义流控规则,流控规则内容为 :QPS 的阈值为 2
  2. 快速连续(频率大于每秒钟 2 次)访问 http://localhost:8501/testF 结果如下:

Spring Cloud Alibaba Sentinel - 图21

通过代码定义流量控制规则

还可以在服务代码中,调用 <font style="color:rgb(36, 41, 46);">FlowRuleManager.loadRules()</font> 方法来定义流控规则,该方法需要一个 FlowRule 类型的 List 集合作为其参数,示例代码如下。

https://www.yuque.com/chenlaohan/xnax4v/akgnzc?inner=eMoQ1

  1. 定义一个 <font style="color:rgb(68, 68, 68);">initFlowRules() </font>方法,为名为 <font style="color:rgb(68, 68, 68);">testD-resource</font> 的资源定义流控规则:每秒最多只能通过 2 个请求,即 QPS 的阈值为 2。在 testF() 方法中调用 initFlowRules() 方法,初始化流控规则
@GetMapping("/testF")
@SentinelResource(value = "testF-resource",blockHandler = "blockHandlerTestF")
public String testF() {
    initFlowQpsRule();
    return "serverPort:[" + serverPort + "],testF……";
}

public String blockHandlerTestF(BlockException exception){
    String str = Thread.currentThread().getName() + "端口[" + serverPort + "]请求被限流,请稍后重试";
    return str;
}

private static void initFlowQpsRule() {
    List<FlowRule> rules = new ArrayList<>();
    //定义一个限流规则对象
    FlowRule rule1 = new FlowRule();
    //资源名称
    rule1.setResource("testF-resource");
    //设置QPS的阈值为2
    rule1.setCount(2);
    //限流阈值的类型
    rule1.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule1.setLimitApp("default");
    rules.add(rule1);
    FlowRuleManager.loadRules(rules);
}
  1. 浏览器访问 http://localhost:8501/testF,每秒访问超过2次

Spring Cloud Alibaba Sentinel - 图22

流控模式

流控模式有一下三种情况

Spring Cloud Alibaba Sentinel - 图23

  • 直接:api达到限流条件时,直接限流
  • 关联:当关联的资源达到阈值时,就限流自己
  • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就进行限流)【api级别的针对来源】

直接(默认)+ 快速失败(默认)

QPS直接快速失败

QPS:query per second,每秒钟的请求数量,当调用该api的QPS达到阈值时,进行限流。

下面设置表示每秒请求两次或以内是OK,若QPS>2,就直接-快速失败,报默认错误

Spring Cloud Alibaba Sentinel - 图24Spring Cloud Alibaba Sentinel - 图25

线程数直接失败

当调用该api的线程数达到阈值的时候,进行限流和QPS类似。

与QPS直接快速失败不同的是,QPS情况下限制的是流量,比如银行的人流量只能是1人/s,也就是说每次只能一个人进入银行办理业务;而线程数就好比银行只有一个窗口开放,一群人都可以进入银行,但是每次只能处理一个人的业务。

Spring Cloud Alibaba Sentinel - 图26

在请求中给线程休眠 0.9秒

@GetMapping("/testG")
public String testG() {
    try {
        Thread.sleep(9000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return "serverPort:[" + serverPort + "],testG……";
}

多次请求,创建多个线程。这里直接报错

Spring Cloud Alibaba Sentinel - 图27

关联

当关联的资源达到阈值时,就限流自己。比如当与A关联的资源B达到阈值后,就限流A自己。使用如下:

创建两个请求资源

@GetMapping("/testG")
public String testG() {
    return "serverPort:[" + serverPort + "],testG……";
}

@GetMapping("/testH")
public String testH() {
    return "serverPort:[" + serverPort + "],testH……";
}

添加流控规则。当请求 资源/testH超过阈值时,限流资源 /testG资源请求

Spring Cloud Alibaba Sentinel - 图28

Postman模拟并发密集访问testG。先创建一个集合,名字自己随便取。

Spring Cloud Alibaba Sentinel - 图29

新建一个组,创建一个请求,请求我们的 http://localhost:8501/testH。选中组创建并发请求

Spring Cloud Alibaba Sentinel - 图30

Spring Cloud Alibaba Sentinel - 图31

请求过程中会发现在请求 http://localhost:8501/testG 就限流了

Spring Cloud Alibaba Sentinel - 图32

链路

作用:只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值。

Sentinel从1.6.3版本开始,Sentinel Web Filter 默认收敛所有的URL入口的Context,因此链路限流不生效 1.7.0版本开始,官方在CommomFilter中引入了WEB_CONTEXT_UNIFY这个init parameter,用于控制是否收敛context,将其配置为false即可根据不同的URL进行链路限流 Spring Cloud Alibaba 在2.1.1.RELEASE版本后,可以通过配置spring.cloud.sentinel.web-context-unify=false关闭

画板

例如现在有两个请求,最终的会请求到 testLink 资源上。我们对其中一个请求进行QPS进行限制则另个一不限制。 /testG ——》 /testLink /testH ——》 /testLink 1. 创建相应文件 java @GetMapping("/testG") public String testG() { String s = flowLimitService.testLink(serverPort); return "get /testG 【"+s+"】"; } @GetMapping("/testH") public String testH() { String s = flowLimitService.testLink(serverPort); return "get /testH 【"+s+"】"; } java package com.chen.springcloudalibabasentinel8501.service; import com.alibaba.csp.sentinel.annotation.SentinelResource; import com.alibaba.csp.sentinel.slots.block.BlockException; import org.springframework.stereotype.Service; import org.springframework.web.bind.annotation.PathVariable; @Service public class FlowLimitService { @SentinelResource(value = "testLink",blockHandler = "catchTestLink") public String testLink(String serverPort) { String str = "serverPort:[" + serverPort + "],testLink……"; return str; } public String catchTestLink(@PathVariable("serverPort") String serverPort, BlockException exception){ return "testLink限流成功"; } } 2. 流控资源规则添加 Spring Cloud Alibaba Sentinel - 图34 3. 测试 + 请求 /testG 的QPS>2时,会进行限流 Spring Cloud Alibaba Sentinel - 图35 + 任意请求/testH,都无问题,不会进行限流 :::info Sentinel 流控模式中的关联类型和链路类型的区别:
  • 关联 :假设A规则关联B,那么A资源是受限制的
  • 链路 :假设A规则绑定了一个链路 关联B,那么受限制的是B

:::

流控效果

快速失败

默认的流控效果,直接失败,抛出异常。可以参考上方所写过的:https://www.yuque.com/chenlaohan/xnax4v/akgnzc#j8UNT

Warm Up

刚开始把 阈值调低,不要让过多的请求访问服务器,导致冲垮服务器,先让服务器一点一点处理,再慢慢加量

预热公式:阈值 除以 coldFactor(默认值为3),经过预热时长后才会达到阈值

默认coldFactor为3,即请求QPS从(threshold / 3)开始,经多少预热时长才逐渐升至设定的QPS阈值。

如下案例,阀值为10,预热时长设置5秒。

Spring Cloud Alibaba Sentinel - 图36
系统初始化的阀值为10 / 3约等于3,即阀值刚开始为3,然后经过 5秒后阀值才慢慢升高恢复到10。这样做的目的就是防止瞬间高并发导致系统奔溃

排队等待

排队等待(匀速器):匀速排队,让请求以匀速的速度通过,阈值类型必须设置为QPS,否则无效。匀速排队方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。详细可参考官网:flow-control 例如:/testF的QPS最大为1,超过的话就排队等待,等待的超时时间为20000ms。 java @GetMapping("/testH") public String testH() { String str = Thread.currentThread().getName()+":testH"; log.info(str); return str; } Spring Cloud Alibaba Sentinel - 图37 最后我们可以通过Postman来进行测试,发送请求时没有延迟,同时发送10条请求,然后我们会发现就是排队效果1秒执行一个请求,请求日志如下
2022-08-24 15:01:09.324  INFO 10980 --- [nio-8501-exec-7] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-7:testH
2022-08-24 15:01:10.324  INFO 10980 --- [nio-8501-exec-6] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-6:testH
2022-08-24 15:01:11.325  INFO 10980 --- [nio-8501-exec-8] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-8:testH
2022-08-24 15:01:12.325  INFO 10980 --- [nio-8501-exec-5] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-5:testH
2022-08-24 15:01:13.325  INFO 10980 --- [nio-8501-exec-9] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-9:testH
2022-08-24 15:01:14.324  INFO 10980 --- [io-8501-exec-10] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-10:testH
2022-08-24 15:01:15.324  INFO 10980 --- [nio-8501-exec-2] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-2:testH
2022-08-24 15:01:16.324  INFO 10980 --- [nio-8501-exec-1] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-1:testH
2022-08-24 15:01:17.325  INFO 10980 --- [nio-8501-exec-4] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-4:testH
2022-08-24 15:01:18.325  INFO 10980 --- [nio-8501-exec-3] c.c.s.controller.FlowLimitController     : http-nio-8501-exec-3:testH

熔断降级规则

除了流量控制以外,对调用链路中不稳定资源的熔断降级,也是保障服务高可用的重要措施之一。 在分布式微服务架构中,一个系统往往由多个服务组成,不同服务之间相互调用,组成复杂的调用链路。如果链路上的某一个服务出现故障,那么故障就会沿着调用链路在系统中蔓延,最终导致整个系统瘫痪。Sentinel 提供了熔断降级机制就可以解决这个问题。 Sentinel 的熔断将机制会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),暂时切断对这个资源的调用,以避免局部不稳定因素导致整个系统的雪崩。
熔断降级作为服务保护自身的手段,通常在客户端(调用端)进行配置,资源被熔断降级最直接的表现就是抛出 DegradeException 异常。

官网参考:circuit-breaking

Sentinel 熔断策略

Sentinel 提供了 3 种熔断策略,如下表所示。
慢调用比例 (SLOW_REQUEST_RATIO) 选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大响应时间),若请求的响应时间大于该值则统计为慢调用。 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则再次被熔断。
异常比例 (ERROR_RATIO) 当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目且异常的比例大于阈值,则在接下来的熔断时长内请求会自动被熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。
异常数 (ERROR_COUNT) 当单位统计时长内的异常数目超过阈值之后会自动进行熔断。 经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

Sentinel 熔断降级配置规则

Spring Cloud Alibaba Sentinel - 图38
熔断降级规则(DegradeRule)包含下面几个重要的属性:

Field 说明 默认值
资源名 即规则的作用对象
熔断策略 支持三种策略 慢调用比例/异常比例/异常数 慢调用比例
最大RT 请求的最大响应时间,请求的响应时间大于该值则统计为慢调用
熔断时长 熔断开启状态持续的时间,超过该时间熔断器会切换为探测恢复状态(HALF-OPEN),单位为 <font style="color:rgb(68, 68, 68);">s</font>
最小请求数 熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入) 5
统计时长 熔断触发需要统计的时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入) 1000 ms
比例阈值 分为慢调用比例阈值和异常比例阈值,即慢调用或异常调用占所有请求的百分比,取值范围 [0.0,1.0](1.8.0 引入)
异常数 请求或调用发生的异常的数量(注:策略为异常数策略下可设置

Sentinel 熔断状态

Sentinel 1.8.0版本对熔断降级做了大的调整,可自定义任意时长的熔断时间,引入了半开启恢复支持。熔断状态有三种状态,非别为<font style="color:rgb(77, 77, 77);">OPEN、HALF_OPEN、CLOSED</font>

状态 说明 触发条件
熔断关闭状态(CLOSED) 处于关闭状态时,请求可以正常调用资源。 满足以下任意条件,Sentinel 熔断器进入熔断关闭状态:
+ 全部请求访问成功。
+ 单位统计时长(statIntervalMs)内请求数目小于设置的最小请求数目。
+ 未达到熔断标准,例如服务超时比例、异常数、异常比例未达到阈值。
+ 处于探测恢复状态时,下一个请求访问成功。
熔断开启状态(OPEN) 处于熔断开启状态时,熔断器会一定的时间(规定的熔断时长)内,暂时切断所有请求对该资源的调用,并调用相应的降级逻辑使请求快速失败避免系统崩溃。 满足以下任意条件,Sentinel 熔断器进入熔断开启状态:
+ 单位统计时长内请求数目大于设置的最小请求数目,且已达到熔断标准,例如请求超时比例、异常数、异常比例达到阈值。
+ 处于探测恢复状态时,下一个请求访问失败。
探测恢复状态(HALF-OPEN) 处于探测恢复状态时,Sentinel 熔断器会允许一个请求调用资源。则若接下来的一个请求成功完成(没有错误)则结束熔断,熔断器进入熔断关闭(CLOSED)状态;否则会再次被熔断,熔断器进入熔断开启(OPEN)状态。 在熔断开启一段时间(降级窗口时间或熔断时长,单位为 s)后,Sentinel 熔断器自动会进入探测恢复状态。

慢调用比例

  1. 编写业务测试方法
@GetMapping("/testI")
public String testI() {
    String str =  "serverPort:[" + serverPort + "],testI,测试慢调用比例RT";
    try {
        //暂停1秒
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info(str);
    return str;
}
  1. 配置给资源熔断规则

此配置代表 在1000ms统计时长内,总请求数超过5次请求有80%的最大RT超过200ms的就进行熔断2s

Spring Cloud Alibaba Sentinel - 图39

  1. Jmeter压力测试

使用Jmeter模拟 1s请求10个线程(大于最小请求数5个的设置)调用/testI

第一步:添加线程组,设置线程数和下方时间。下方表示1s请求10次
Spring Cloud Alibaba Sentinel - 图40
第二步:添加一个请求
Spring Cloud Alibaba Sentinel - 图41
Spring Cloud Alibaba Sentinel - 图42
第三步:发送请求
Spring Cloud Alibaba Sentinel - 图43

Spring Cloud Alibaba Sentinel - 图44

应为程序中设置了休眠 1000s,从实时监控可以看出只是第一个线程请求是OK的,后续9个线程请求都被限流了。

异常比例

Spring Cloud Alibaba Sentinel - 图45

1000ms统计时长内,大于5次的请求中超过80%的请求出现异常,则熔断2s

@GetMapping("/testI")
public String testI() {
    String str =  "serverPort:[" + serverPort + "],testI,测试慢调用比例RT";
    try {
        //暂停1秒
        TimeUnit.MILLISECONDS.sleep(1000);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    log.info(str);
    int i = 10 / 0; //并发测试这里模拟异常
    return str;
}

Jmeter 单独访问一次,必然来一次报错一次(int age = 10/0),调一次错一次;开启jmeter后,直接高并发发送请求,多次调用达到我们的配置条件了。断路器开启(保险丝跳闸),微服务不可用了,不再报错error而是服务降级了。

Spring Cloud Alibaba Sentinel - 图46

异常数

统计时长1000ms内,超过5个请求中有3个请求异常的熔断2s

Spring Cloud Alibaba Sentinel - 图47

浏览器频繁访问 ,会发现次数达到后进行熔断

Spring Cloud Alibaba Sentinel - 图48

热点参数限流

何为热点:热点即经常访问的数据,有时候我们希望统计或者限制某个热点数据中访问频次最高的数据,并对其访问进行限流。使用如下:

案例使用

  1. 定义业务方法
@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "blockExceptionTestHotKey")
public String testHotkey(@RequestParam(value = "p1", required = false) String p1,
                         @RequestParam(value = "p2", required = false) String p2) {
    return "serverPort:[" + serverPort + "],testHotkey...";
}

//这里是我们自定义的兜底方法,BlockException不要打成了BlockedException
public String blockExceptionTestHotKey(String p1, String p2, BlockException e) {
    return "testHotkey自定义限流提示:blockExceptionTestHotKey╰(*°▽°*)╯...";
}
  1. 定义热点限制规则

热点规则共有资源名、限流模式(只支持QPS模式)、参数索引、单机阈值、统计窗口时长、是否集群6种参数,还有一些高级选项,用到时会详细介绍。这里会用到注解中的value作为资源名,兜底方法会在后面详细介绍

Spring Cloud Alibaba Sentinel - 图49

资源名****唯一路径,默认为请求路径。此处必须是 @SentinelResource 注解的 value 属性值,配置@GetMapping 的请求路径无效)

配置热点规则:

绑定testHotKey资源,把testHotKey对应的第一个参数作为热点key进行监控。设定热点限流规则:当该资源的访问QPS超过1次/s的时候,产生限流并执行自定义的blockExceptionTestHotKey兜底方法。

简而言之:方法testHotKey里面第一个参数只要QPS超过每秒1次,马上降级处理。

Spring Cloud Alibaba Sentinel - 图50

  1. 测试

1次/s正常显示,迅速点击两次,触发热点限流,执行自定义兜底方法:

Spring Cloud Alibaba Sentinel - 图51

参数例外项

Spring Cloud Alibaba Sentinel - 图52

上述案例演示了第一个参数h1,当QPS超过1秒1次点击后马上被限流

特例情况:我们期望h1参数当它是某个特殊值时,它的限流值和平时不一样,比如当h1的值等于5时,它的阈值可以达到10。

测试

持久化规则

前面我们微服务新增的限流规则后,微服务关闭重启后就会丢失,当时配置的限流规则都是临时的。 如何进行持久化呢,可以将限流配置规则持久化进Nacos保存,只要刷新服务某个rest地址,sentinel控制台的流控规则 就能看到。只要nacos里面的配置不删除,针对8501上的sentinel上的流控规则就持续存在。 (也可以持久化到文件,redis,数据库等)

  1. 导入持久化需要的依赖,编写业务方法啊
<!--SpringCloud ailibaba sentinel-datasource-nacos 持久化-->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>
@GetMapping("/rateLimit/byUrl")
@SentinelResource(value = "byUrl")
public String byUrl() {
    return "持久化配置限流测试";
}
  1. 修改yaml
server:
  port: 8501

spring:
  application:
    name: chen-sentinel-service
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心地址
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: 127.0.0.1:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8917
      web-context-unify: false
      #持久化配置
      datasource:
        ds1:
          nacos:
            server-addr: 127.0.0.1:8848
            dataId: chen-sentinel-service
            groupId: DEFAULT_GROUP
            data-type: json
            rule-type: flow
management:
  endpoints:
    web:
      exposure:
        include: '*'
  1. nacos添加配置规则

我们将sentinel的流控配置保存在nacos中,因为我们可以把nacos的配置持久化在了数据库中。

Spring Cloud Alibaba Sentinel - 图53

[
    {
        "resource": "/rateLimit/byUrl",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

resource:资源名称;

limitApp:来源应用;

grade:阈值类型,0表示线程数,1表示QPS;

count:单机阈值;

strategy:流控模式,0表示直接,1表示关联,2表示链路;

controlBehavior:流控效果,0表示快速失败,1表示Warm Up,2表示排队等待;

clusterMode:是否集群。

  1. 测试

启动服务访问接口,刷新Sentinel。可以看到Sentinel中加载了通过nacos持久化的规则配置文件。

Spring Cloud Alibaba Sentinel - 图54