SpringCloudAlibaba-Sentinel

本文编写自2021年4月13日,当前控制台最新版本为 2021年2月4日发布的1.8.1版本

本文使用版本控制为
spring-boot-dependencies:2.4.4
spring-cloud-dependencies:2020.0.2
spring-cloud-alibaba-dependencies:2.2.1.RELEASE

本文使用版本为(受版本控制会自动选择,也不用太关注,这里只是展示一下而已)
SpringCloudAlibaba:2.2.1.RELEASE
(其中包含的Sentinel版本:1.7.1)
Sentinel控制台:v1.8.1
SpringBoot:2.4.4

分布式系统的流量防卫兵
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 官网:https://sentinelguard.io/zh-cn/
Sentinel GitHub:https://github.com/alibaba/Sentinel/
Sentinel 中文文档:https://github.com/alibaba/Sentinel/wiki/介绍

就和Hystrix差不多,实现服务降级、服务熔断。

本文默认阅读者已经熟练掌握Maven、SpringBoot等相关知识。
一些概念性东西等,源于官方文档,可以直接阅读官方文档。

概述

什么是 Sentinel

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件,主要以流量为切入点,从流量控制、熔断降级、系统自适应保护等多个维度来帮助您保障微服务的稳定性。

Sentinel 分为两个部分:

  • 核心库(Java 客户端)不依赖任何框架/库,能够运行于所有 Java 运行时环境,同时对 Dubbo / Spring Cloud 等框架也有较好的支持。
  • 控制台(Dashboard)基于 Spring Boot 开发,打包后可以直接运行,不需要额外的 Tomcat 等应用容器。

特征

Sentinel 具有以下特征:

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

Sentinel 的主要特性:

Sentinel 的开源生态

Sentinel 功能和设计理念

流量控制

流量控制在网络传输中是一个常用的概念,它用于调整网络包的发送数据。然而,从系统稳定性角度考虑,在处理请求的速度上,也有非常多的讲究。任意时间到来的请求往往是随机不可控的,而系统的处理能力是有限的。我们需要根据系统的处理能力对流量进行控制。Sentinel 作为一个调配器,可以根据需要把随机的请求调整成合适的形状,如下图所示:

流量控制有以下几个角度:

  • 资源的调用关系,例如资源的调用链路,资源和资源之间的关系;
  • 运行指标,例如 QPS、线程池、系统负载等;
  • 控制的效果,例如直接限流、冷启动、排队等。

Sentinel 的设计理念是让您自由选择控制的角度,并进行灵活组合,从而达到想要的效果。

熔断降级

什么是熔断降级

除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。这个问题和 Hystrix 里面描述的问题是一样的。


Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。

熔断降级设计理念

在限制的手段上,Sentinel 和 Hystrix 采取了完全不一样的方法。
Hystrix 通过线程池的方式,来对依赖(在我们的概念中对应资源)进行了隔离。这样做的好处是资源和资源之间做到了最彻底的隔离。缺点是除了增加了线程切换的成本,还需要预先给各个资源做线程池大小的分配。
Sentinel 对这个问题采取了两种手段:

  • 通过并发线程数进行限制

和资源池隔离的方法不同,Sentinel 通过限制资源并发线程的数量,来减少不稳定资源对其它资源的影响。这样不但没有线程切换的损耗,也不需要您预先分配线程池的大小。当某个资源出现不稳定的情况下,例如响应时间变长,对资源的直接影响就是会造成线程数的逐步堆积。当线程数在特定资源上堆积到一定的数量之后,对该资源的新请求就会被拒绝。堆积的线程完成任务后才开始继续接收请求。

  • 通过响应时间对资源进行降级

除了对并发线程数进行控制以外,Sentinel 还可以通过响应时间来快速降级不稳定的资源。当依赖的资源出现响应时间过长后,所有对该资源的访问都会被直接拒绝,直到过了指定的时间窗口之后才重新恢复。

系统负载保护

Sentinel 同时提供系统维度的自适应保护能力。防止雪崩,是系统防护中重要的一环。当系统负载较高的时候,如果还持续让请求进入,可能会导致系统崩溃,无法响应。在集群环境下,网络负载均衡会把本应这台机器承载的流量转发到其它的机器上去。如果这个时候其它的机器也处在一个边缘状态的时候,这个增加的流量就会导致这台机器也崩溃,最后导致整个集群不可用。
针对这个情况,Sentinel 提供了对应的保护机制,让系统的入口流量和系统的负载达到一个平衡,保证系统在能力范围之内处理最多的请求。

对比

Sentinel & Hystrix:
image.png

下载安装Sentinel控制台

Sentinel这个东西使用的时候只需要导入一个pom依赖就好了,不需要像Nacos一样需要下载一个服务并运行。
但是,Sentinel它有一个控制台,这个东西是单独一个jar工程,需要我们单独下载并运行的。

下载

我们现在是2021年4月13日,最新版本控制台是2021年2月4日更新的 v1.8.1

两种方式:

  • 从最新版本的源码自行构建 Sentinel 控制台:
  • release 页面 下载最新版本的控制台 jar 包。

下载源码并编译

  • 下载 控制台 工程
  • 使用以下命令将代码打包成一个 fat jar: mvn clean package

下载编译好的jar包

进入https://github.com/alibaba/Sentinel/releases页面获取最新的Sentinel控制台jar包。
(当然你也可以根据需要寻找旧版本下载)
也可以从我的csdn下载:https://download.csdn.net/download/wangguohui0726/16660808

启动

因为是jar包项目,所以无需安装,直接启动即可。
控制台配置的规则(流控规则、熔断规则……)都是临时的。微服务重启就会消失。

注意:启动 Sentinel 控制台需要 JDK 版本为 1.8 及以上版本。
使用如下命令启动控制台(最后面的文件名据实修改):

java -Dserver.port=8080 -Dcsp.sentinel.dashboard.server=localhost:8080 -Dproject.name=sentinel-dashboard -jar sentinel-dashboard.jar

其中 -Dserver.port=8080 用于指定 Sentinel 控制台端口为 8080,也可修改成自己指定的端口。

从 Sentinel 1.6.0 起,Sentinel 控制台引入基本的登录功能,默认用户名和密码都是 sentinel。可以参考 鉴权模块文档 配置用户名和密码。

注:若您的应用为 Spring Boot 或 Spring Cloud 应用,您可以通过 Spring 配置文件来指定配置,详情请参考 Spring Cloud Alibaba Sentinel 文档

启动之后的页面(默认用户名和密码都是 sentinel):
http://localhost:8080/#/login
image.png
登录之后页面(默认用户名和密码都是 sentinel):
image.png
Sentinel控制台采用的是懒加载的机制,哪怕你有别的服务使用了控制台,他这里初始也不显示,需要你访问一次那个服务的接口之后,刷新后才会展示。如果不理解,看到后面用的时候就知道了。

Sentinel的代码案例

SpringCloudAlibaba环境使用(其他使用查看官方文档):
先自己创建一个maven或是Spring Initializr项目,然后再创建我们所需要的子模块,我们要创建好多个子模块,作为服务的提供者和消费者。具体创建过程项目、子模块过程略。。。
我创建的项目名称叫做 SpringCloudAlibabaSentinel

对于依赖管理,我们可以在项目的 pom.xml 中加入如下配置控制SpringCloudAlibaba各组件的版本。
具体获取位置:在我们进入到官方文档后,左侧目录第二项 **2. Dependency Management **里面就有。
页面位置链接:https://spring-cloud-alibaba-group.github.io/github-pages/hoxton/en-us/index.html#_dependency_management
image.png

最终完整版父项目的 pom.xml 文件添加以下配置,统一管理子模块的依赖坐标版本(如果父pom不写也行,那么每个子模块就都要写一遍了)。

    <packaging>pom</packaging>

		<dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>2.4.4</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
            <dependency>
                <groupId>com.alibaba.cloud</groupId>
                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
                <version>2.2.1.RELEASE</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

官方demo

https://github.com/alibaba/spring-cloud-alibaba/wiki/Sentinel
创建子模块–>改pom–>写配置–>写代码–>启动
pom.xml

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
</dependency>

SpringMVC代码

@SpringBootApplication
public class Application {

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

@Service
public class TestService {

    @SentinelResource(value = "sayHello")
    public String sayHello(String name) {
        return "Hello, " + name;
    }
}

@RestController
public class TestController {

    @Autowired
    private TestService service;

    @GetMapping(value = "/hello/{name}")
    public String apiHello(@PathVariable String name) {
        return service.sayHello(name);
    }
}

SpringWebflux代码

@SpringBootApplication
public class Application {

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

}

@RestController
public class TestController {

    @GetMapping("/mono")
    public Mono<String> mono() {
	return Mono.just("simple string");
    }

}

application.yml

server:
  port: 9031
spring:
  cloud:
    sentinel:
      transport:
        # 这个是微服务和控制台交互的端口,默认8719,冲突时自增寻找不冲突的使用
        port: 8719
        # 这个填写我们的Sentinel控制台对应地址
        dashboard: localhost:8080
  application:
    name: AliDemo

然后启动,访问对应接口,可以在控制台看到响应监控信息
image.png

流量控制

学习此处建议先阅读官方文档 [Sentinel工作主流程](Sentinel 工作主流程),了解其相关概念。
然后阅读 官方文档-流量控制

总体介绍

我们在Sentinel的控制台上面可以看到一个叫做流控规则的菜单,在这里面我们可以看到已经创建好的流控规则,右上角可以创建新的流控规则:
image.png
image.png
也可以在簇点链路菜单里直接对某个接口进行配置:
image.png
然后我们对这个流控规则进行一个解释:

  • 资源名: 唯一名称,就是我们mvc配置的请求路径
  • 针对来源: Sentinel可以针对调用者(微服务名)进行限流,默认default(不区分来源)
  • 阈值类型/单机阈值
    • QPS(每秒请求数量):当调用该接口的QPS达到阈值的时候,进行限流
    • 线程数:当调用该接口的线程数达到阈值的时候,进行限流
  • 是否集群: (勾选和不勾选的配置项会有差别)
    • 勾选:是集群
    • 未勾选:不集群
  • 阈值:能够允许的 QPS/线程数 最大值
    • 单机阈值:非集群情况下,单机节点的阈值
    • 均摊阈值:集群环境下、单机均摊模式下,每个节点的QPS/线程数阈值
    • 总体阈值:集群环境下、总体阈值模式下、整个集群的QPS/线程数阈值
  • 流控模式
    • 直接:接口达到限流条件时,直接限流
    • 关联:当关联的资源达到限流阈值时,就限流自己
    • 链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到峰值,就进行限流)
  • 流控效果
    • 快速失败:直接抛异常
    • Warm Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/coldFactor,经过预热时长,才达到设置的QPS阈值
    • 排队等待:匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效
  • 失败退化: 如果 Token Server 不可用是否退化到单机限流
    • 勾选:退化
    • 未勾选:不退化

流控模式

流控模式分为三种,直接、关联、链路(上面也说了)。

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

直接

这里只是简单使用并展示Sentinel的流控功能,更深入的使用,我们后面再说,先不要考虑我们怎么配置失败后的指定页面或者啥啥啥的。
以我们已有的服务为例子,对我们的 /hello/{name} 接口进行限流。
左侧菜单->簇点链路->/hello/{name}接口->流控->填写配置信息->新增

阈值类型:QPS,阈值:1:
代表我访问此接口的时候,一秒内连续访问超过1次会被限流。
image.png
然后它会自动跳转到"链路规则"菜单,右侧展示我们配置的流控规则。
image.png
然后进行验证:
未添加流控规则的时候,我们访问http://localhost:9031/hello/aaa 无论怎么访问,访问多少次都是没问题的。
image.png
当我们配置了阈值为1的流控规则的时候,当我们连续访问此接口超过1时,会展示如下内容。
image.png
说明我们的限流配置成功了。

之前我们配置的是QPS的,然后我们再尝试一下线程数的
阈值类型:线程数,阈值:1:
代表我访问此接口的时候,一秒内超过一个线程访问会被限流。
将流控规则中的阈值类型修改为线程数并保存。然后我们像之前一样疯狂访问,发现并没有什么效果,无论怎么访问都ok。
这是因为,我们当前配置的是线程数,不是QPS了,我们在一个标签页访问,无论怎么访问都是一个线程,一直没有超出阈值,所以就没有看到被限流的页面了。
我们可以再增加一个标签页,两个标签页都是访问这个接口,然后两个页面来回切换,并快速刷新(刷新就相当于访问了),只要手速够快,我们就会发现有一个标签页看到了被限流的页面。(如果手速不够,可以把配置修改的长一点,比如阈值改为2秒、3秒……)
image.png

关联

这个模式是在一个接口达到设定的阈值之后,对另外一个接口进行流控的操作。
为了能够实验,我们本来只有一个接口,我们将 /hello/{name} 接口复制一份,叫做 /hello2/{name} 并重启服务。(别忘记了Sentinel控制台是懒加载的,要想页面展示接口,我们需要都访问一遍)
配置:

这里我们就只展示一个QPS类型的吧,线程数的情况的话,直接模式的看懂了这里线程数的也就会了。

image.png
然后我们启动jmeter或者是postman或其他的工具对 /hello2/{name} 接口进行0.3秒一次的循环访问,启动后我们再对/hello/{name}接口进行访问,就会发现 /hello/{name} 接口被限流了。
我这里用的是jmeter,工具怎么使用我这里就不说了。不过手速快的话,两个标签页,一个hello2,一个hello,疯狂访问hello2,然后访问一次hello也能展示出效果。
image.pngimage.pngimage.png

链路

链路限流是相当于配置某一条链路访问到这个api才会导致限流,下面展示我们的接口结构图以及控制台配置图
image.pngimage.png
就比如我配置的api是sayHello这个方法(需要加上@SentinelResource注解),入口是 /hello/123 ,这时候,我们通过/hello/123 访问 sayHello 这个方法达到阈值是会进行限流的,但是仅仅只是对 /hello/123 调用 sayHello 这条链路进行限流,/hello2/123 调用 sayHello 是不会被限流的。
image.pngimage.png

但是呢,有个问题,如果按照我的版本来进行学习的话,这个限流是失败的,根本没有上述的限流效果,这是为什么呢?
从 1.6.3 版本开始,Sentinel Web filter 默认收敛所有 URL 的入口 context,因此链路限流不生效。1.7.0 版本开始(对应 SCA 2.1.1.RELEASE),我们在 CommonFilter 引入了 WEB_CONTEXT_UNIFY 这个 init parameter,用于控制是否收敛 context(入口资源关闭是否聚合)。将其配置为 false 即可根据不同的 URL 进行链路限流。

我们需要进行以下配置(记得重启):
添加一个pom依赖并添加一个配置类,然后重新配置限流就可以了

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-web-servlet</artifactId>
        </dependency>
@Configuration
public class FilterContextConfig {
    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        // 入口资源关闭聚合
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "false");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        return registration;
    }
}

我们再看一下配置前和配置后的控制台差别:
配置前:
image.png
配置后:
image.png
我们可以明显看出来,配置了入口资源关闭聚合之后,sayHello不会再合并了,每一个接口都有一份了。
再有,也可以观察到这样的一个现象:你调用 /hello/123 的时候,只有 /hello/123 下面的 sayHello 的分钟通过会增加1,而 /hello2/123 下面的 sayHello 是不会增加的。

流控效果

流控模式分为三种,快速失败、Warm Up、排队等待(上面也说了)。

  • 快速失败:直接抛异常
  • Warm Up:根据coldFactor(冷加载因子,默认3)的值,从阈值/coldFactor,经过预热时长,才达到设置的QPS阈值
  • 排队等待:匀速排队,让请求以匀速通过,阈值类型必须设置为QPS,否则无效

快速失败

默认的流控效果。
快速失败就是在我们达到阈值的时候直接抛异常。我们之前的代码、案例都是使用的快速失败模式。

Warm Up

官方描述:https://github.com/alibaba/Sentinel/wiki/流量控制#warm-up
我们先对 /hello/{name} 接口进行一个WarmUp效果的限流配置。
image.png
此配置的含义:单机阈值6,预热时长3
在我们刚开始ide时候它会根据 阈值/coldFactor 规则进行流控,因为coldFactor默认是3,也就是说刚刚开始的时候,阈值是6/3=2,直到预热时长(3秒)时间达到了之后,才会将阈值提升到6,其过程是逐步提升的。
配置之后我们可以开始访问接口 /hello/{name} 进行测试。刚开始的3秒内,我们如果一秒内访问超过2次,就会看到限流现象,在3秒之后,我们一秒内访问超过6次才会产生限流现象(一秒6次用手动刷新挺费劲,所以一般看到的都是无论我怎么访问都没有限流,因为手动没有达到一秒6次访问啊,如果非要看到限流效果,找个工具比如jmeter进行访问)。

匀速排队

官方描述:https://github.com/alibaba/Sentinel/wiki/流量控制#匀速排队
简单描述下就是:无论你来多少个请求,我每秒只处理阈值量的请求,其余多的请求我也不报错,都在后面拍着,等前面的请求处理完之后再进行处理。
匀速排队只允许阈值类型是QPS类型,不支持线程数类型,利用的是漏桶算法

为了展示排队效果,我们将代码中添加一句打印语句:
image.png
控制台限流配置:
image.png
然后我们开始进行测试,疯狂访问 http://localhost:9031/hello/12323 然后观察控制台内容。我们会发现,虽然我们是连着疯狂请求的,但是控制台是每隔一秒打印一句,说明了他是每一秒执行一次请求。
image.png

那下面的超时时间是干嘛的?
我们可以想象成所有的请求都是放在了一个队列里等待执行,如果我队列里的任务超出了设置的等待时间,那么这个请求就会超时报错(超时时间是以毫秒为单位)。

这个就不演示了,我懒了……

熔断降级

官方文档:https://sentinelguard.io/zh-cn/docs/circuit-breaking.html
Sentinel的服务熔断、降级和Hystrix的熔断、降级是很像的。
旧版本的Sentinel的熔断是没有半开状态的(Hystrix有),但是!新版1.8的有!!!
根据新建降级规则页面内容,我们可以了解到,Sentinel的熔断策略一共有三个:慢调用比例(也就是旧版本的RT)、异常比例、异常数
image.png
Sentinel 提供以下几种熔断策略:

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

慢比例调用

选择以慢调用比例作为阈值,需要设置允许的慢调用 RT(即最大的响应时间),请求的响应时间大于该值则统计为慢调用。当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且慢调用的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
所以我们能够看出,熔断规则为:请求响应时间大于最大RT 并且 单位统计时长内请求数目大于最小请求数

image.png
在这里我们可以看到,慢比例调用有5个配置值

  • 最大RT: 单位毫秒,最大的响应时间,超过该值则记为慢调用
  • 比例阈值: 0到1,就是达到多少之后会进行熔断
  • 熔断时长: 单位秒,经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求响应时间小于设置的慢调用 RT 则结束熔断,若大于设置的慢调用 RT 则会再次被熔断。
  • 最小请求数: 触发熔断的最小请求数目,若当前统计窗口内的请求数小于此值,即使达到熔断条件规则也不会触发
  • 统计时长: 单位毫秒,就是判断熔断时的单位时间

总体来说就是:在统计时长时间内,某个接口的请求数大于最小请求数、请求响应时间大于最大RT的请求比例大于比例阈值的时候会进行熔断。熔断的时间为熔断时长,在熔断时长达到后,会尝试进入半开状态,如果下一个请求时长大于RT继续熔断,小于则恢复正常。

然后我们进行一下配置并尝试。
此配置表示:一秒内 /hello/{name} 接口的请求数超过2、并且有一半的请求超过了800毫秒就进行熔断,熔断时间为2秒。
image.png
然后为了保证接口请求时长超过800毫秒,我们改造下代码,让它sleep1秒。
image.png
然后我们疯狂访问会发现确实被熔断了
image.png
在熔断期间2秒内我们再次请求发现还是被熔断的,然后我们等待2秒,再次请求会发现熔断结束了。
image.png

但是吧,我发现他这里有个Bug,就是我新建的时候我的比例阈值是0.5,可是当我编辑的时候,它回显的是1。
还有统计时长也是,无论我设置的是多少,编辑的时候都是1000。

异常比例

当单位统计时长(statIntervalMs)内请求数目大于设置的最小请求数目,并且异常的比例大于阈值,则接下来的熔断时长内请求会自动被熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

让我们看一下这个配置页面:
统计时长内,如果接口收到的请求大于最小请求数,并且出错的请求比例大于比例阈值,那么就会进行熔断,熔断时间为熔断时长

我们来演示一下这个效果:
Hello/{name} 接口进行修改,让他每次都报错,然后重启:

比如我设置比例阈值为1,最小请求数为2,熔断时间3秒,统计时间1秒。
那么就会在1秒内接收到两次以上请求,并且请求都报错的时候进行熔断,熔断3秒后恢复。

之后我们访问 http://localhost:9031/hello/12323 ,结果如下:

  • 一秒内访问次数小于等于2次的的时候,页面只会报错,并没有进行熔断。

  • 一秒内访问次数大于2次的时候,页面开始从报错页面转变成了熔断页面。

  • 当熔断触发的时候,我继续访问还是会一直熔断(展示熔断页面),当我停止访问3秒后,再次进行访问,发现熔断结束了(展示报错页面)。

异常数

当单位统计时长内的异常数目超过阈值之后会自动进行熔断。经过熔断时长后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

其实异常数和异常比例很像,只不过是从比例转变成了具体的数量了而已。
如果直接一看就懂了就不需要看这一段的内容了,直接跳过就行了,我写只是为了文档的完整。

熔断效果展示:

  1. 删除之前的熔断规则,保证环境的干净,不会被其他规则影响
  2. 使用异常比例熔断规则的代码就可以。
  3. 配置熔断规则

  1. 验证
  • 在一秒内如果访问次数超过2次,异常次数超过1次,进行熔断,熔断时间3秒。
  • 经过3秒后熔断器会进入探测恢复状态(HALF-OPEN 状态),若接下来的一个请求成功完成(没有错误)则结束熔断,否则会再次被熔断。

热点参数限流

根据前面的讲述,限流规则肯定已经比较熟悉了。然而,在Sentinel中,还有一种单拿出来的一种限流,也就是此部分的热点参数限流
相比之下,热点参数限流就是在普通的限流功能上,增加了对于指定参数的限流功能,也是一个比较实用的限流功能。
描述一个功能场景:比如我们有一个查询商品接口,这个接口我们会经常访问,访问量特别大,我们需要进行限流(比如一秒内只能查询100次)。但是里面有几个特殊的商品,我们需要查询它的时候能够有一些特例,比如id为6(也就是指定对应特例参数的值)的数据可以一秒钟内查询100000次,这样的时候我们就可以用到热点参数限流功能。如果觉得这么描述还是不容易理解,我又举了个例子:
比如我有一个接口 /goods/findById?id= 经常会用到,并发量特别高,我需要对这个接口进行一个限流处理,但是id为6的商品是一个我收了广告费的商品,那我就需要在查询这个商品的时候提高查询时限流的阈值,这时候我就可以使用热点参数限流,对 /goods/findById 接口进行限流100,对id为6的特例限流100000。
我觉得这回应该是能理解了。

然后我们来看一下控制台配置页面:

然后我们解释一下配置信息的各个参数
基础配置:

  • 资源名:@SentinelResource 注解配置的值
  • 参数索引: 第几个索引,从0开始,以java代码中的参数为准,而不是url中的。它只关注你指定索引的参数,其他索引位置的参数他不管。
  • 单机阈值: 单位时间内达到的限流的访问量最大值
  • 统计窗口时长: 统计多久的时间内的请求量

高级选项:

  • 参数类型: 就是参数的类型。8个基本类型除去short、boolean再加上String,一共七种。
  • 参数值: 恩,就是这个参数的值。在值是这个值得时候,使用这个例外项的配置内容。
  • 限流阈值: 在请求的参数值符合配置的例外项的时候,使用此例外项对应的阈值。

验证:
首先我们把代码恢复到这样

然后启动项目,访问接口(因为控制台懒加载),进入控制台,配置热点参数限流。

然后我们访问该接口,一秒内访问一次的时候没问题,一秒钟内访问超过两次的时候它就会进行限流。

然后我们添加一个参数例外项,值为abc的限流阈值修改为100(只影响值为100的,其他的值还是使用上面的1)。

再对 http://localhost:9031/hello/12323 进行访问,毫无疑问,限流效果还是1秒1个请求。
然后再访问 http://localhost:9031/hello/abc 无论我们怎么刷新页面(就相当于访问),都是展示正常的,不会因被限流展示报错页面。然后我们为了展示100确实控制到了,我是用jmeter进行访问。设置好地址 http://localhost:9031/hello/abc 访问量101,一口气全部发送。


执行之后我们可以看到,101个请求只有最后一个失败了,前100个都成功了,证明了我们这个100的限流特例生效了。

post请求的有点问题还没搞懂,对接口已经创建特例了,但是就是没生效,还是访问第二次就报错。


系统自适应限流

在配置页面中是 系统规则

系统规则支持以下的模式:

  • Load 自适应(仅对 Linux/Unix-like 机器生效):系统的 load1 作为启发指标,进行自适应系统保护。当系统 load1 超过设定的启发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护(BBR 阶段)。系统容量由系统的maxQps * minRt估算得出。设定参考值一般是CPU cores * 2.5。
  • CPU usage(1.5.0+ 版本):当系统 CPU 使用率超过阈值即触发系统保护(取值范围 0.0-1.0),比较灵敏。
  • 平均 RT:当单台机器上所有入口流量的平均 RT 达到阈值即触发系统保护,单位是毫秒。
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值即触发系统保护。
  • 入口 QPS:当单台机器上所有入口流量的 QPS 达到阈值即触发系统保护。

具体演示就不掩饰了,和之前的没差多少。

@SentinelResource

@SentinelResource注解就相当于Hystrix的@HystrixCommand注解。
@SentinelResource注释指示Sentinel资源的定义。
在之前我们就配置过@SentinelResource这个注解,主不过是不知道它是什么意思、有什么作用而已,这里我们就对它进行一个简单的讲解。

功能与参数

注解参数详细内容查看以下两个链接,这里只是简单介绍:

通过查看源码,我们可以看到该注解一共有这么多个属性:
image.png
然后我们对它一一进行解释。

  • value: Sentinel资源的名称,我们不仅可以通过url进行限流,也可以把此值作为资源名配置,一样可以限流。(下一段就说的这个)
  • entryType: 条目类型(入站或出站),默认为出站
  • resourceType: 资源的分类(类型)
  • blockHandler: 块异常函数的名称,默认为空
  • blockHandlerClass: 块处理程序所在的类不应提供多个类
    • 默认情况下, blockHandler与原始方法位于同一类中。 但是,如果某些方法共享相同的签名并打算设置相同的块处理程序,则用户可以设置存在块处理程序的类。 请注意,块处理程序方法必须是静态的。
  • fallback: 后备函数的名称,默认为空
  • defaultFallback: 默认后备方法的名称,默认为空
    • defaultFallback用作默认的通用后备方法。 它不应接受任何参数,并且返回类型应与原始方法兼容
  • fallbackClass: fallback方法所在的类(仅单个类)
    • 默认情况下, fallback与原始方法位于同一类中。 但是,如果某些方法共享相同的签名并打算设置相同的后备,则用户可以设置存在后备功能的类。 请注意,共享的后备方法必须是静态的。
  • exceptionsToTrace: 异常类的列表追查, Throwable默认
  • exceptionsToIgnore: 要忽略的异常类列表,默认情况下为空

相关问题解决方案

在之前的使用过程中,我们肯定会发现虽然功能是体现出来了,但是我们在实际开发中并不能只是做到这样就行了,我们还需要更丰富完善的功能,所以我们这里提出了几个比较重要的问题以及解决方案。

  • 限流返回结果是系统默认的,并没有返回我们想要的结果。
  • 依照现有的条件,我们自定义的处理方法又和业务代码耦合在一起,不直观。
  • 每个业务方法都添加一个兜底的,那代码膨胀加剧。
  • 全局统一的处理方法没有体现。

主要使用@SentinelResource注解的fallback、fallbackClass、blockHandler、blockHandlerClass四个注解实现异常和流控的兜底方案。

规则持久化

我们之前在控制台配置流控、降级规则时候,会发现一个问题,微服务重启了之后相应的规则配置就会自动消失,并没有进行保存,再次使用需要重新配置。这在生产环境上可是巨大的灾难啊,配置了几十个几百个,重启一下,没了,那不能行那不能行,那我们要怎么搞?
我们可以将配置保存在MySQL、nacos……中,这里用nacos举例。
所有能保存的中间件以及保存方式查阅:https://github.com/alibaba/Sentinel/wiki/动态规则扩展

在pom文件中添加如下依赖

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>

application.yml中添加:
在nacos的控制台添加如下配置:

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

image.png
字段含义:
image.png
然后,我们访问一次接口之后,可以发现,在Sentinel控制台的流控规则中可以看到我们刚在nacos上配置的规则。

相关推荐
<p> <strong><span style="font-size:20px;color:#FF0000;">本课程主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的Java学习者</span></strong> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">1. 包含:<span style="color:#FFFF00;background-color:#FF0000;">项目源码、</span><span style="color:#FFFF00;background-color:#FF0000;">项目文档、数据库脚本、软件工具</span>等所有资料</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">2. 手把手的带你从零开始部署运行本套系统</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">3. 该项目附带的源码资料可作为毕设使用</span></strong></span> </p> <p> <span style="color:#FF0000;"><strong><span style="font-size:18px;">4. 提供技术答疑和远程协助指导</span></strong></span><strong><span style="font-size:18px;"></span></strong> </p> <p> <br /> </p> <p> <span style="font-size:18px;"><strong>项目运行截图:</strong></span> </p> <p> <strong><span style="font-size:18px;">1)系统登陆界面</span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015433522.png" alt="" /><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">2)学生模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241015575966.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">3)教师模块</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016127898.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">4)系统管理员</span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016281177.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><img src="https://img-bss.csdn.net/202002241016369884.png" alt="" /></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p> <p> <strong><span style="font-size:18px;"><strong><span style="font-size:18px;">更多Java毕设项目请关注我的毕设系列课程 <a href="https://edu.csdn.net/lecturer/2104">https://edu.csdn.net/lecturer/2104</a></span></strong></span></strong> </p> <p> <strong><span style="font-size:18px;"><br /> </span></strong> </p>
<p> 课程演示环境:Windows10  </p> <p> 需要学习<span>Ubuntus</span>系统<span>YOLOv4-tiny</span>的同学请前往《<span>YOLOv4-tiny</span>目标检测实战:训练自己的数据集》 <span></span> </p> <p> <span> </span> </p> <p> <span style="color:#E53333;">YOLOv4-tiny</span><span style="color:#E53333;">来了!速度大幅提升!</span><span></span> </p> <p> <span> </span> </p> <p> <span>YOLOv4-tiny</span>在<span>COCO</span>上的性能可达到:<span>40.2% AP50, 371 FPS (GTX 1080 Ti)</span>。相较于<span>YOLOv3-tiny</span>,<span>AP</span>和<span>FPS</span>的性能有巨大提升。并且,<span>YOLOv4-tiny</span>的权重文件只有<span>23MB</span>,适合在移动端、嵌入式设备、边缘计算设备上部署。<span></span> </p> <p> <span> </span> </p> <p> 本课程将手把手地教大家使用<span>labelImg</span>标注和使用<span>YOLOv4-tiny</span>训练自己的数据集。课程实战分为两个项目:单目标检测(足球目标检测)和多目标检测(足球和梅西同时检测)。<span></span> </p> <p> <span> </span> </p> <p> 本课程的<span>YOLOv4-tiny</span>使用<span>AlexAB/darknet</span>,在<span>Windows10</span>系统上做项目演示。包括:<span>YOLOv4-tiny</span>的网络结构、安装<span>YOLOv4-tiny</span>、标注自己的数据集、整理自己的数据集、修改配置文件、训练自己的数据集、测试训练出的网络模型、性能统计<span>(mAP</span>计算<span>)</span>和先验框聚类分析。 <span> </span> </p> <p> <span> </span> </p> <p> 除本课程《<span>Windows</span>版<span>YOLOv4-tiny</span>目标检测实战:训练自己的数据集》外,本人推出了有关<span>YOLOv4</span>目标检测的系列课程。请持续关注该系列的其它视频课程,包括:<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:训练自己的数据集》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:人脸口罩佩戴识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测实战:中国交通标志识别》<span></span> </p> <p> 《<span>Windows</span>版<span>YOLOv4</span>目标检测:原理与源码解析》<span></span> </p> <p> <span> <img alt="" src="https://img-bss.csdnimg.cn/202007061503586145.jpg" /></span> </p> <p> <span><img alt="" src="https://img-bss.csdnimg.cn/202007061504169339.jpg" /><br /> </span> </p>
©️2020 CSDN 皮肤主题: 点我我会动 设计师:白松林 返回首页