SpringCloudAlibaba之Sentinel流量控制、熔断降级详解,实战图文演示

Sentinel 介绍

分布式系统的流量防卫兵,随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。

  1. 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。

  2. 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。

  3. 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。

  4. 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

  5. 官网文档:https://sentinelguard.io/zh-cn/docs/introduction.html

Sentinel 功能和设计理念

流量控制

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

在这里插入图片描述
流量控制有以下几个角度:

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

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

熔断降级

除了流量控制以外,降低调用链路中的不稳定资源也是 Sentinel 的使命之一。由于调用关系的复杂性,如果调用链路中的某个资源出现了不稳定,最终会导致请求发生堆积。
在这里插入图片描述
Sentinel 和 Hystrix 的原则是一致的: 当调用链路中某个资源出现不稳定,例如,表现为 timeout,异常比例升高的时候,则对这个资源的调用进行限制,并让请求快速失败,避免影响到其它的资源,最终产生雪崩的效果。

服务雪崩

多个微服务之间调用的时候,假设A调用B和C,B和C又调用其他的微服务,这就是所谓的扇出。如果扇出的某个链路上某个微服务调用的响应时间过长或者不可用,微服务A的调用就用占用越来越多的系统资源,从而引起系统崩溃,这也就是服务雪崩。其实就是服务的高可用遭到了破坏。

​要解决这种问题的出现我们就需要用到服务降级,而Sentinel就可以保证在一个依赖出现问题的情况下,不会导致整体服务失败,避免级联故障,提高分布式系统的弹性。

Sentinel的熔断降级通过断路器实现:

断路器:它本身是一种开关装置,当某个服务单元发生故障之后,通过断路器的故障监控(类似于熔断保险丝),向调用方返回一个符合预期的、可处理的备选响应(FallBack),而不是长时间的等待或者抛出调用方法无法出的异常,这样就保证了服务调用方的不会被长时间、不必要的占用,从而避免了故障在分布式系统中蔓延(类似于病毒传染),从而避免了故障在系统中蔓延,乃至崩溃。

Sentinel下载和安装

​下载地址:https://github.com/alibaba/Sentinel/releases

Sentinel 分为两个部分

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

启动步骤

  • 前提:jdk1.8环境和8080端口不能被占用

  • 启动命令:java -jar sentinel-dashboard-1.8.2.jar

  • 访问地址:localhost:8080

  • 输入默认账号密码:sentinel/sentinel

搭建Sentinel项目

  1. Sentinel的官方文档网址:https://sentinelguard.io/zh-cn/docs/quick-start.html

  2. 创建项目sentinel-8401

  3. 导入依赖:

    <!-- Nacos客户端依赖 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
    </dependency>
    <!-- sentinel依赖 -->
    <dependency>
        <groupId>com.alibaba.cloud</groupId>
        <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    </dependency>
    
  4. 配置properties文件,目的是让当前8401注册进Nacos,然后被Sentinel8080进行监控

    # 应用名称
    spring.application.name=sentinel-8401
    server.port=8401
    spring.cloud.nacos.discovery.username=nacos
    spring.cloud.nacos.discovery.password=nacos
    # Nacos 服务发现与注册配置,其中子属性 server-addr 指定 Nacos 服务器主机和端口
    spring.cloud.nacos.discovery.server-addr=127.0.0.1:8848
    
    spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080
    spring.cloud.sentinel.transport.clientIp=127.0.0.1
    spring.cloud.sentinel.transport.port=8719
    spring.cloud.sentinel.web-context-unify=false
    
    # 注册到 nacos 的指定 namespace,默认为 public
    management.endpoints.web.exposure.include=*
    
    feign.sentinel.enabled=true
    
  5. 编写SentinelController

    @RestController
    public class SentinelController {
    
        @Autowired
        private SentinelService sentinelService;
    
        @Value("${server.port}")
        private String port;
    
        @GetMapping("sentinel")
        public String sentinelTest() {
            return "sentinel " + port;
        }
    
    
        @GetMapping("testA")
        public String testA() {
            sentinelService.sayHello();
            return "testA " + port;
        }
     }
    
  6. 访问本地服务接口 http://localhost:8401/testA

    在这里插入图片描述

  7. 访问本地Senttinel http://localhost:8080/#/dashboard/home

    在这里插入图片描述

Sentinel流量控制

在这里插入图片描述

名词解释

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

Sentinel流控规则-QPS/线程数-直接失败

QPS直接失败案例

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

线程数直接失败案例

在这里插入图片描述
QPS和并发线程数规则详解
在这里插入图片描述

    @GetMapping("testA")
    public String testA() {
        try {
            Thread.sleep(1000);
        }catch (Exception e){
            e.printStackTrace();
        }
        sentinelService.sayHello();
        return "testA " + port;
    }

在这里插入图片描述

Sentinel流控规则-关联

​官方解释:当关联的资源达到阈值时,就限流自己。

​通俗解释来说,比如那我们的程序,现在有testA接口和testB接口,当A关联的资源B达到阈值后,就限流自己,也就是B到达阈值,限流A本身。就好像我家孩子在外面打架,我来处理一样。换到程序里面来说比如一个电商系统中,支付系统达到阈值,就限流下订单系统。

在这里插入图片描述

具体演示

​当关联资源**/testB的qps阈值超时1时,就限流/testA**的Rest访问地址,当关联资源到阈值后限制配置好的资源名

为了演示效果,所以这里我们需要借助一个工具Postman,来模仿并发密集访问/testB,先来测试访问testB接口

在这里插入图片描述

在这里插入图片描述

Sentinel流控规则-链路

​ 链路流控模式指的是,当从某个接口过来的资源达到限流条件时,开启限流,它的功能有点类似于针对来源配置项,区别在于:针对来源是针对上级微服务,而链路流控是针对上级接口,也就是说它的粒度更细。

​ 比如在一个微服务中,两个接口都调用了同一个Service中的方法,并且该方法用SentinelResource(用于定义资源)注解标注了,然后对该注解标注的资源(方法)进行配置,则可以选择链路模式。

在这里插入图片描述

具体演示

首先我们编写一个Service

@Service
public class SentinelService {

    @SentinelResource(value="hello" )
    public void sayHello(){
        System.out.println("hello");
    }
}

@RestController
public class SentinelController {

    @Autowired
    private SentinelService sentinelService;

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


    @GetMapping("testA")
    public String testA() {
        sentinelService.sayHello();
        return "testA " + port;
    }

    @GetMapping("testB")
    public String testB() {
        sentinelService.sayHello();
        return "testB " + port;
    }
  }

流控规则:

这里要注意不要对/testA或者/testB进行限流规则的配置,要给用SentinelResource注解标注的资源进行配置限流规则,这里的意思为当我们用入口资源访问被SentinelResource注解标注的资源方法时,当超过阈值就会被限流。

在这里插入图片描述

快速访问/testB接口就会被限制

在这里插入图片描述

Sentinel流控效果-预热

概念:Warm Up方式,即预热/冷启动方式。该方式主要用于系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过"冷启动",让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮的情况。

​预热公式:阈值/coldFactor(默认值为3),经过预热时间后才会达到阈值。

流控规则:

在这里插入图片描述

使用场景:一般秒杀系统中会有这样的流控设置,为了防止秒杀瞬间造成系统崩溃。

具体演示

​ 默认coldFactor为3,当发起请求即请求QPS从(阈值/3)开始,经过多长预热时长才逐步升至设定的QPS阈值,当前阈值设置为10,预热时长设置为5秒。

​ 最终的效果,系统初始化时阈值/3约等于3,即阈值在此时为3,经过5秒后阈值才慢慢升高到10

测试,我们用最简单的方法进行测试,直接在浏览器上手动刷新,然后我们来看Sentinel的实时监控

在这里插入图片描述

Sentinel流控效果-排队等待

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

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

在这里插入图片描述

匀速器

​它的中心思想是,以固定的间隔时间让请求通过。当请求到来的时候,如果当前请求距离上个通过的请求通过的时间间隔不小于预设值,则让当前请求通过。否则,计算当前请求的预期通过时间,如果该请求的预期通过时间小于规则预设的 timeout 时间,则该请求会等待直到预设时间到来通过(排队等待处理);若预期的通过时间超出最大排队时长,则直接拒接这个请求。
在这里插入图片描述
Sentinel 匀速排队等待策略是漏桶算法结合虚拟队列等待机制实现的。

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

流控规则:

在这里插入图片描述

在这里插入图片描述

Sentinel 熔断降级

熔断策略

Sentinel 提供以下几种熔断策略

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

Sentinel在1.8.0版本对熔断降级做了大的调整,可以定义任意时长的熔断时间,引入了半开启恢复支持。下面梳理下相关特性。

熔断状态有三种状态,非别为OPEN、HALF_OPEN、CLOSED

状态说明
OPEN表示熔断开启,拒绝所有请求
HALF_OPEN探测恢复状态,如果接下来的一个请求顺利通过则表示结束熔断,否则继续熔断
CLOSE表示熔断关闭,请求顺利通过

熔断规则

熔断降级规则包含下面几个重要的属性:

Field说明默认值
resource资源名,即规则的作用对象
grade熔断策略,支持慢调用比例/异常比例/异常数策略慢调用比例
count慢调用比例模式下为慢调用临界 RT(超出该值计为慢调用);异常比例/异常数模式下为对应的阈值
timeWindow熔断时长,单位为 s
minRequestAmount熔断触发的最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断(1.7.0 引入)5
statIntervalMs统计时长(单位为 ms),如 60*1000 代表分钟级(1.8.0 引入)1000 ms
slowRatioThreshold慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)

慢调用比例

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

在这里插入图片描述


    @GetMapping("testB")
    public String testB() throws InterruptedException {
        sentinelService.sayHello();
        Thread.sleep(500);
        return "testB " + port;
    }

在这里插入图片描述

异常比例

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

在这里插入图片描述

    @GetMapping("testB")
    public String testB(@RequestParam(value ="id") Integer id) {
        sentinelService.sayHello();
        if("1".equals(id)){
            System.out.println(1/0);
        }
        return "testB " + port;
    }

在这里插入图片描述

异常数

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

在这里插入图片描述

    @GetMapping("testB")
    public String testB(@RequestParam(value ="id") Integer id) {
        sentinelService.sayHello();
        if("1".equals(id)){
            System.out.println(1/0);
        }
        return "testB " + port;
    }

在这里插入图片描述

热点规则

何为热点?热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:

  • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
  • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

热点参数限流会统计传入参数中的热点参数,并根据配置的限流阈值与模式,对包含热点参数的资源调用进行限流。热点参数限流可以看做是一种特殊的流量控制,仅对包含热点参数的资源调用生效
在这里插入图片描述

Sentinel 利用 LRU 策略统计最近最常访问的热点参数,结合令牌桶算法来进行参数级别的流控。

使用@SentinelResource注解

其实这个热点限流其实就是更加细粒度的流控规则,那么如果想使用它就必须要配合对应SentinelResource注解。

Sentinel 提供了 @SentinelResource 注解用于定义资源,它有很多的参数,我们这里主要关注两个参数:

  1. value:代表资源名称,必需项,因为需要通过resource name找到对应的规则,这个是必须配置的
  2. blockHandler:blockHandler 对应处理 BlockException 的方法名称,可选项,访问范围需要是 public,返回类型需要与原方法相匹配,参数类型需要和原方法相匹配并且最后加一个额外的参数,类型为 BlockException。
@RestController
public class TestController {

    @GetMapping("/test")
    @SentinelResource(value = "test",blockHandler = "testHandler")
    public String test(@RequestParam(value ="userName",required = false ) String userName,@RequestParam(value = "pwd",required = false) String pwd){
        User user=new User();
        user.setUserName(userName);
        user.setPwd(pwd);
        return "正常结束  data="+user.toString();
    }

    public String testHandler(String userName,String pwd, BlockException e){
        return "特殊处理";
    }
}

在这里插入图片描述

在这里插入图片描述

参数例外项

​其实参数例外项就是可以达到更加细粒度的控制,比如我们当前的例子中,目前userName参数在访问时超过阈值就会被限流,但是我们可以通过参数例外项设置userName具体等于特殊的某个值的时候,触发不同的限流效果。假如userName的值等于(zhangshan)时,它的阈值可以达到100。

在这里插入图片描述

在这里插入图片描述

Sentinel 系统规则

​系统保护规则是从应用级别的入口流量进行控制,从单台机器的 load、CPU 使用率、平均 RT、入口 QPS 和并发线程数等几个维度监控应用指标,让系统尽可能跑在最大吞吐量的同时保证系统整体的稳定性。

​ 系统保护规则是应用整体维度的,而不是资源维度的,并且仅对入口流量生效。入口流量指的是进入应用的流量,比如 Web 服务或 Dubbo 服务端接收的请求,都属于入口流量。

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

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

在这里插入图片描述

在这里插入图片描述

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值