Spring Cloud Alibaba Sentinel 熔断与限流(一)

一、Sentinel 

Sentinel 是由阿里巴巴中间件团队开发的开源项目,是一种面向分布式微服务架构的轻量级高可用流量控制组件。Sentinel 主要以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度帮助用户保护服务的稳定性。Sentinel 具有以下优势:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的“双十一”大促流量的核心场景,例如秒杀(将突发流量控制在系统可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用服务等。
  • 完备的实时监控:Sentinel 提供了实时监控功能。用户可以在控制台中看到接入应用的单台机器的秒级数据,甚至是 500 台以下规模集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供了开箱即用的与其它开源框架或库(例如 Spring Cloud、Apache Dubbo、gRPC、Quarkus)的整合模块。我们只要在项目中引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。此外,Sentinel 还提供 Java、Go 以及 C++ 等多语言的原生实现。
  • 完善的 SPI 扩展机制:Sentinel 提供简单易、完善的 SPI 扩展接口,我们可以通过实现这些扩展接口快速地定制逻辑,例如定制规则管理、适配动态数据源等。

SPI ,全称为 Service Provider Interface,是一种服务发现机制。它可以在 ClassPath 路径下的 META-INF/services 文件夹查找文件,并自动加载文件中定义的类。

从功能上来说,Sentinel 与 Spring Cloud Netfilx Hystrix 类似,但 Sentinel 要比 Hystrix 更加强大,例如 Sentinel 提供了流量控制功能、比 Hystrix 更加完善的实时监控功能等等。

二、Sentinel主要特征

网址:https://github.com/alibaba/Sentinel

 

三、Sentinel 的组成

Sentinel 由以下两个部分组成:

  • Sentinel 核心库:Sentinel 的核心库不依赖任何框架或库,能够运行于 Java 8 及以上的版本的运行时环境中,同时对 Spring Cloud、Dubbo 等微服务框架提供了很好的支持。
  • Sentinel 控制台(Dashboard):Sentinel 提供的一个轻量级的开源控制台,它为用户提供了机器自发现、簇点链路自发现、监控、规则配置等功能。

Sentinel 核心库不依赖 Sentinel Dashboard,但两者结合使用可以有效的提高效率,让 Sentinel 发挥它最大的作用。

四、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 是用于配置和管理规则(例如流控规则、熔断降级规则等)的。使用sentinel不仅可以对规则进行配置和管理,还能实时查看规则的效果。

安装 Sentinel 控制台下面我们就来演示下,如何下载和安装 Sentinel 控制台,具体步骤如下。

1. 使用浏览器访问 Sentinel Dashboard 下载页面下载 Sentinel 控制台的 jar 包,如下图。

2. 打开命令行窗口,跳转到 Sentinel Dashboard  jar 包所在的目录,执行以下命令,启动 Sentinel Dashboard。

java -jar sentinel-dashboard-1.8.6.jar

3.启动完成后,使用浏览器访问 http://localhost:8080/,跳转到 Sentinel 控制台登陆页面,如下图:

4. 分别输入用户名和密码(默认都是 sentinel),点击下方的登录按钮,结果如下图。

六、Sentinel 的开发流程说明和案例演示

Sentinel 的开发流程如下:

  1. 引入 Sentinel 依赖:在项目中引入 Sentinel 的依赖,将 Sentinel 整合到项目中;
  2. 定义资源:通过对主流框架提供适配或 Sentinel 提供的显式 API 和注解,可以定义需要保护的资源,此外 Sentinel 还提供了资源的实时统计和调用链路分析;
  3. 定义规则:根据实时统计信息,对资源定义规则,例如流控规则、熔断规则、热点规则、系统规则以及授权规则等。
  4. 检验规则是否在生效:运行程序,检验规则是否生效,查看效果。

6.1.首先需求启动Naocs

这里要和nacos配合使用,所以先启动nacos,

6.2.创建模块

创建maven模块,名字为:cloudalibaba-sentinel-service8401,如下图:

6.2.在pom.xml中引入依赖

这里注意nacos和sentinel的依赖都需要引入

<dependencies>
        <!--Nacos 服务发现依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--Snetinel 依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

6.3.创建配置文件

创建application.yml 配置文件,添加内容如下:

server:
  port: 8401 #端口
spring:
  application:
    name: springcloudalibaba-sentinel-service #服务名
  cloud:
    nacos:
      discovery:
        #Nacos服务注册中心(这是是Windows上的,也可以集群)地址
        server-addr: localhost:8848
    sentinel:
      transport:
        #配置 Sentinel dashboard 地址
        dashboard: localhost:8080
        #默认8719端口,假如被占用会自动从8719开始依次+1扫描,直至找到未被占用的端口
        port: 8719
management:
  endpoints:
    web:
      exposure:
        include: '*'

6.4.创建主启动类

在com.augus.cloud包下创建SpringCloudAlibabaSentinelService8401Application主启动类

package com.augus.cloud;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

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

6.5.创建controller

在 com.augus.cloud 下,创建一个名为 SentinelController 的 Controller 类,代码如下:

package 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 SentinelController {
    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/testA")
    public String testA() {
        return "服务访问成功------testA";
    }
    @GetMapping("/testB")
    public String testB() {
        return "服务访问成功------testB";
    }
}

6.6.测试

依次启动 Nacos Server 、sentinel控制台、 spring-cloud-alibaba-sentinel-service-8401,使用浏览器访问“http://localhost:8401/testA”,结果如下图:

6.7. 登录Sentinel 控制台

使用浏览器访问 Sentinel 控制台主页,在sentinel“首页”下方新增了一个 springcloudalibaba-sentinel-service 的菜单,而这正是 spring-cloud-alibaba-sentinel-service-8401 的服务名(spring.application.name),说明 Sentinel 已经监控到这个服务,如下图:

6.8. 点击sentinel “实时监控”

将http://localhost:8401/testA 多访问基础,查看 sentinel-service 下各请求的实时监控数据,如下图所示:

七、定义资源

资源是 Sentinel 中的核心概念之一。在实际项目开发的时候,只需要考虑这个服务、方法或代码是否需要保护,如果需要保护,就可以将它定义为一个资源。Sentinel 定义资源的方式有:

    • 适配主流框架自动定义资源
    • 通过 SphU 手动定义资源
    • 通过 SphO 手动定义资源
    • 注解方式定义资源

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

Sentinel 对主流框架进行了适配,只要引入相关的适配模块(例如 spring-cloud-starter-alibaba-sentinel),Snetinel 就会自动将项目中的服务(包括调用端和服务端)定义为资源,资源名就是服务的请求路径。此时,我们只要再定义一些规则,这些资源就可以享受到 Sentinel 的保护。可以在 Sentinel 控制台的“簇点链路”中,直接查看被 Sentinel 监控的资源,启动8401模块,在浏览器访问:http://localhost:8401/testA,如下图:

 

 

7.2.通过 SphU 手动定义资源

Sentinel 提供了  SphU 的类,它包含的 try-catch 风格的 API ,可以实现手动定义资源。

7.2.1. 在 cloudalibaba-sentinel-service-8401 下的 SentinelController 中添加内容

新增一个 testC() 方法,然后定义一个名为 testCbySphU 的资源,testC的返回值 是testCbySphU方法,代码如下。

package com.augus.cloud.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphO;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SentinelController {
    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/testA")
    public String testA() {
        return "服务访问成功------testA";
    }
    @GetMapping("/testB")
    public String testB() {
        return "服务访问成功------testB";
    }


    @GetMapping("/testC")
    public String testC(){
        return testCbySphU();
    }/**
     * 通过Sphu手动定义资源
     * @return
     */
    public String testCbySphU(){
        Entry entry=null;

        try {
            //业务逻辑-开始
            entry = SphU.entry("testCBySpho");
            return "服务访问成功 testC:"+serverPort;
        } catch (BlockException e) {
            e.printStackTrace();
            return "testC 服务被限流";
            //流控逻辑处理-结束
        }finally {
            if(entry!=null){
                entry.exit();
            }
        }

    }
}

7.2.2.重启 cloudalibaba-sentinel-service-8401

使用浏览器访问 http://localhost:8401/testC 结果如下:

服务访问成功 testC:8401

7.2.3. 访问 Sentinel 控制台主页,点击 sentinel-service 下的“簇点链路”

结果如下图:

7.3.通过 SphO 手动定义资源

Sentinel 还提供了一个名为 SphO 的类,它包含了 if-else 风格的 API,能帮助我们手动定义资源。通过这种方式定义的资源,发生了限流之后会返回 false,此时我们可以根据返回值,进行限流之后的逻辑处理。

7.3.1. 在 cloudalibaba-sentinel-service-8401 下的 SentinelController 中添加内容,

新增一个 testDbySphO() 方法定义一个名为 testDbySphO 的资源,代码如下:

package com.augus.cloud.controller;

import com.alibaba.csp.sentinel.Entry;
import com.alibaba.csp.sentinel.SphO;
import com.alibaba.csp.sentinel.SphU;
import com.alibaba.csp.sentinel.slots.block.BlockException;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SentinelController {
    @Value("${server.port}")
    private String serverPort;

    @GetMapping("/testA")
    public String testA() {
        return "服务访问成功------testA";
    }
    @GetMapping("/testB")
    public String testB() {
        return "服务访问成功------testB";
    }


    @GetMapping("/testC")
    public String testC(){
        return testCbySphU();
    }

    @GetMapping("/testD")
    public String testD(){
        return testDbySphO();
    }
    
    /**
     * 通过Sphu手动定义资源
     * @return
     */
    public String testCbySphU(){
        Entry entry=null;

        try {
            //业务逻辑-开始
            entry = SphU.entry("testCBySpho");
            return "服务访问成功 testC:"+serverPort;
        } catch (BlockException e) {
            e.printStackTrace();
            return "testC 服务被限流";
            //流控逻辑处理-结束
        }finally {
            if(entry!=null){
                entry.exit();
            }
        }
    }

    /**
     * 通过SphO 手动定义资源
     * @return
     */
    public String testDbySphO(){
        if(SphO.entry("testDbySphO")){
            //务必保证finally被执行
            try {
                return "服务访问成功------testD:" + serverPort;
            }finally {
                SphO.exit();
            }
        }else {
            //资源访问阻止,被限流或者降级
            //流控开始
            return "testD 服务被限流";
            //流控结束
        }
    }
}

7.3.2. 重启 spring-cloud-alibaba-sentinel-service-8401,

使用浏览器访问 http://localhost:8401/testD ,结果如下:

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

除了以上两种方式外,我们还可以通过 Sentinel 提供的 @SentinelResource 注解定义资源。

7.4.1. 将 cloudalibaba-sentinel-service-8401 中 SentinelController 类中增加代码:

新增内容如下:

@GetMapping("/testE")
    @SentinelResource(value = "testEbyAnnotation") //通过注解定义资源
    public String testE(){
        return "服务访问成功------testE:" + serverPort;
    }

7.4.2. 重启 spring-cloud-alibaba-sentinel-service-8401

使用浏览器访问 http://localhost:8401/testE,结果如下:

服务访问成功------testE:8401

7.4.3. 访问 Sentinel 控制台主页,点击 sentinel-service 下的“簇点链路”

结果如下图:

八、Sentinel 流量控制

系统处理请求的能力是有限的,但任意时间内到达系统的请求数量,是随机不可控的,如果在某一个瞬时时刻请求量急剧增,那么系统就很有可能被瞬时的流量高峰冲垮。为了避免此类情况发生,就需要根据系统的处理能力对请求流量进行控制,这就是我们常说的“流量控制”,简称“流控”。流量控制是Sentinel 最主要的工作之一。使用Sentinel 可以针对资源定义流控规则,Sentinel 会根据设置的规则对流量相关的各项指标进行监控。当这些指标达到或超过流控规则规定的阈值时,Sentinel 会对请求的流量进行限制(即“限流”),以避免系统被瞬时的流量高峰冲垮,保障系统的高可用性。

流量规则主要由下表中的属性组成,可以通过组合这些属性来实现不同的限流效果。

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

需要注意,同一个资源可以创建多条流控规则,Sentinel 会遍历这些规则,直到有规则触发限流或者所有规则遍历完毕为止。Sentinel 触发限流时,资源会抛出 BlockException 异常,此时我们可以捕捉 BlockException 来自定义被限流之后的处理逻辑。
详细的流控规则配置,参考:https://sentinelguard.io/zh-cn/docs/flow-control.html

8.1.流控模式

8.1.1.直接

  • 流控模式默认是直接,使用浏览器访问:http://localhost:8401/testA,如下图:
服务访问成功------testA
  • 访问 Sentinel 控制台主页,点击 sentinel-service 下的“簇点链路”,选择testA,点击 “流控”,出现如下页面

  •  添加流控规则

  • 手动发出请求或者通过jmeter进行发送,访问http://localhost:8401/testA,设置如下所示:

连续不断的刷新3次,发出三个请求即可。

  • 到Sentinel控制台的实时监控可以看到

  • 上述阈值类型选择的是QPS,那么后面阈值类型选择:线程组

  • 修改testA方法的代码,添加sleep等待。模拟一个线程的处理业务代码需要的时间
@GetMapping("/testA")
    public String testA() throws InterruptedException {
        //等待0.8s
        TimeUnit.MILLISECONDS.sleep(800);
        return "服务访问成功------testA";
    }
  • 利用jmeter模拟多个线程请求访问该方法,发送请求

  • 在控制台查看结果

8.1.2.链路

链路模式:只针对从指定链路访问到本资源的请求做统计,判断是否超过阈值
例如:有两个接口都能访问到该接口

/testA->/testC
/testB->/testC

如果只是想统计从/testB进入到/testC的请求,这是就可以通过流控模式链路来实现,指定入口

案例:有查询订单和创建订单业务,两者都需要查询商品。针对查询订单进入到查询商品的请求统计,并设置限流

  • 在com.augus.cloud包下创建service包

在里面创建:QueryService,代码如下: Sentinel默认只标记Controller中的方法为资源,如果要标记其它方法,需要利用@SentinelResource注解,下面方法必须要加上这个注解

package com.augus.cloud.service;

import com.alibaba.csp.sentinel.annotation.SentinelResource;
import org.springframework.context.annotation.Configuration;

@Configuration
public class QueryService {

    @SentinelResource("products")
    public void QueryProducts() {
        System.err.println("查询商品");
    }
}
  • 在 SentinelController 中添加如下内容

通过 /order/query 和 /order/save访问上面service层的QueryProducts

@Autowired
    private QueryService queryService;

    @GetMapping("/order/query")
    public String queryOrder(){
        //查询商品
        queryService.QueryProducts();

        System.err.println("我是查询订单");

        return "订单查询成功";
    }

    @GetMapping("/order/save")
    public String querySave(){
        //查询商品
        queryService.QueryProducts();

        System.err.println("我是新增订单");
        return "订单查询成功";
    }
  • 修改application.yml配置文件

在配置文件关闭context,就可以让controller里的方法单独成为一个链路;不关闭context的话,controller里的方法都会默认进去sentinel默认的根链路里,这样就只有一条链路,无法流控链路模式

web-context-unify: false # 关闭 context 整合

如下图所示:

 

但是这里有个坑,从1.6.3 版本开始,Sentinel Web filter 默认收敛所有URL的入口 context,因此链路限流不生效。1.7.0 版本开始(对应SCA的2.1.1.RELEASE,网盘之前刚好用的2.1.0.RELEASE不得行),官方在 CommonFilter 引入了WEB_CONTEXT_UNIFY 参数,用于控制是否收敛context。将其配置为 false 即可根据不同的URL 进行链路限流。为了解决这个问题,我将版本换成了2.2.5 版本,也就是可以直接用这个 web-context-unify: false 来使链路限流生效

<spring-cloud-alibabersion>2.2.5.RELEASE</spring-cloud-alibaba.version>
  • 启动之后,并到网页里分别访问了/order/query和/order/save接口后

访问地址:http://localhost:8401/order/query 和 http://localhost:8401/order/save

  • 添加规则

其中对/order/query访问的products做限制,而对/order/save访问products没有做限制

  • 利用jemter进行测试

  • 执行脚本

  • 观察sentinel的实时监控,如下所示

 

8.1.3.关联

  • 关联模式 :统计与当前资源相关的另一个资源,触发阈值时,对当前资源限流
  • 使用场景 :比如用户支付时需要修改订单状态,同时用户要查询订单。查询和修改操作会争抢数据库锁,产生竞争。业务需求是有限支付和更新订单的业务,因此当修改订单业务触发阈值时,需要对查询订单业务限流。

 需求:  

在OrderController新建两个端点:/order/query和/order/update,无需实现业务  
配置流控规则,当/order/update资源被访问的QPS阈值超过5时,对/order/query请求限流
  • 在sentinelController中添加内容如下:
@GetMapping("/order/query")
    public String queryOrder(){
        return "订单查询成功";
    }

    @GetMapping("/order/update")
    public String updateOrder(){
        return "更新订单成功";
    }
  • 添加规则

  • 借助jmeter进行测试

设置循环不断的去请求 http://localhost:8401/order/update 

  • 在网页访问:http://localhost:8401/order/update 

会发现/order/update 访问依然是正常的

 

  • 在网页访问:http://localhost:8401/order/query

/order/query 被限流了

  • 注意:满足下面条件可以使用关联模式

1. 两个有竞争关系的资源   

2. 一个优先级较高,一个优先级较低(优先级高的触发阈值时(上面/order/update),对优先级低的限流(本案例的/order/query))

8.2.流控效果

流控效果是指请求达到流控阈值时应该采取的措施,包括三种:

  • 快速失败:达到阈值后,新的请求会被立即拒绝并抛出FlowException异常。是默认的处理方式。
  • warm up:预热模式,对超出阈值的请求同样是拒绝并抛出异常。但这种模式阈值会动态变化,从一个较小值逐渐增加到最大阈值。
  • 排队等待:让所有的请求按照先后次序排队执行,两个请求的间隔不能小于指定时长

8.2.1.快速失败

快速失败是默认的流控效果,请求被拒绝后抛出FlowException,之前在演示流控模式的一直在使用,就不在这里多说了

8.2.2.Warm up

Warm up也叫预热模式,是应对服务冷启动的一种方案。请求阈值初始值是 threshold(阈值) / coldFactor(预热因子),持续指定时长后,逐渐提高到threshold值。而coldFactor的默认值是3。当系统长期处于低水位的情况下,流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。比如刚启动的服务,数据库连接池可能还未初始化,缓存也处于空的状态,这时候激增的流量非常容易导致服务崩溃。这时我们就可以利用 Sentinel 的 Warm-Up 流控模式,控制通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,而不是在一瞬间全部放行。这样可以给冷系统一个预热的时间,避免冷系统被压垮。

  • 对于/testA实现预热

阈值设置为10,预热时长设置为5秒,系统初始化的阈值为10/3,约等于3,即阈值刚喀什为3,然后过了5秒后,阈值才慢慢的升高回复到10,如下图:

  • 查看设置后的规则,如下图

  •  通过jmeter去测试访问 /testA

线程组设置如下,让每秒钟通过10个请求

  • 查看结果,jmeter设置执行如下图:

刚开始的被拒绝处理的请求比较多,会随着预热过程而通过的请求逐渐变多,拒绝逐渐变少

  • 查看sentinel实施监控如下图

也佐证了随着预热通过的请求越来越多,被拒绝的请求在逐渐减少

8.2.3.排队等待

匀速排队(RuleConstant.CONTROL_BEHAVIOR_RATE_LIMITER)方式会严格控制请求通过的间隔时间,也即是让请求以均匀的速度通过,对应的是漏桶算法。

该方式的作用如下图所示:

这种方式主要用于处理间隔性突发的流量,例如消息队列。想象一下这样的场景,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能够在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

注意:匀速排队模式暂时不支持 QPS > 1000 的场景。

  • 对于/testB 请求设置 排队等待的流控效果

  • 查看设置的流控规则

  •  通过jmeter模拟发出请求

设置jmeter请求,http://localhost:8401/testB 线程组设置如下:

  • 执行脚本,在sentinel下查看结果如下

发出请求/TestB的每秒钟请求数是15,绝大多数每次能通过设置的阈值10个请求,而其他都是放在队列里面去了,小部分被拒绝,无论发送的请求量有多大,/testB 处理的都是匀速的,都是10,对于微服务而言,均衡匀速的要比波动好,起到了流量整型的作用

posted @ 2023-02-03 17:16  酒剑仙*  阅读(143)  评论(0)    收藏  举报