Spring Cloud入门教程-Sentinel

一、Sentinel简介

1、Sentinel是什么?
参考官网:https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5.
在这里插入图片描述
一句话:就是Hystrix

2、Sentinel与Hystrix的区别
Hystrix需要程序员自己手动搭建监控平台,没有一套web界面可以给我们进行更加细粒度化的配置监控、速率控制、服务熔断、服务降级等。Sentinel是一个单独的组件,可以独立出来,直接界面化的细粒度统一配置。

3、下载
链接: https://github.com/alibaba/Sentinel/tags.
选择版本,本案例使用的是sentinel-dashboard-1.7.0.jar

4、Sentinel的作用
流量控制、熔断降级、系统自适应保护
在这里插入图片描述
Sentinel分为两部分:

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

5、运行
命令行切换到jar包目录,“java -jar sentinel-dashboard-1.7.0.jar”
在这里插入图片描述
启动后访问http://localhost:8080/,账号密码:Sentinel
在这里插入图片描述

二、入门案例

1、新建cloud-alibaba-sentinel-service8401工程
在这里插入图片描述

2、pom

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>cloud2020</artifactId>
        <groupId>com.atguigu.springcloud</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>cloud-alibaba-sentinel-service8401</artifactId>

    <dependencies>
        <dependency><!-- 引入自己定义的api通用包,可以使用Payment支付Entity -->
            <groupId>com.atguigu.springcloud</groupId>
            <artifactId>cloud-api-commons</artifactId>
            <version>${project.version}</version>
        </dependency>
        <!--SpringCloud ailibaba nacos -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel-datasource-nacos 后续做持久化用到-->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
        <!--SpringCloud ailibaba sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>
        <!--openfeign-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-openfeign</artifactId>
        </dependency>
        <!-- SpringBoot整合Web组件+actuator -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>
        <!--日常通用jar包配置-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>4.6.3</version>
        </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>

</project>

3、application.yml

server:
  port: 8401

spring:
  application:
    name: cloud-alibaba-sentinel-service
  cloud:
    nacos:
      discovery:
        # 服务注册中心地址
        server-addr: localhost:8848
    sentinel:
      transport:
        # 配置sentinel dashboard地址
        dashboard: localhost:8080
        # 默认 8719端口,假如被占用从8719开始+1扫描直到直到未被占用的端口
        port: 8719

management:
  endpoints:
    web:
      exposure:
        include: '*'

4、主启动类

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

5、业务类

@RestController
@Slf4j
public class FlowLimitController {

    @GetMapping("/testA")
    public String testA()
    {
        return "------testA";
    }

    @GetMapping("/testB")
    public String testB()
    {
        log.info(Thread.currentThread().getName()+"\t"+"...testB");
        return "------testB";
    }
}

6、依次启动Nacos、Sentinel、3377Nacos微服务、8401微服务
在Sentinel web界面查看,发现并未显示8401服务,需要访问服务后才能检测到服务
在这里插入图片描述
在这里插入图片描述

三、流控规则

在这里插入图片描述
资源名:唯一名称,默认请求路径

针对来源:Sentinel可以针对调用者进行限流,填写微服务名,默认default(不区分来源)

阈值类型/单机阈值

  • QPS(每秒钟的请求数量):当调用该api的QPS达到阈值的时候,进行限流
  • 线程数:当调用该api的线程数达到阈值的时候,进行限流

是否集群:(不)需要集群

流控模式

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

流控效果

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

1、流控模式——直接(默认)+快速失败
QPS:
在这里插入图片描述
每秒内请求超过1次,就报错,即限流。
在这里插入图片描述
线程数
在这里插入图片描述
此模式表示只有一个线程处理用户的请求,用户的请求可以进来,但是当没有线程处理的时候,就会失败。

2、流控模式——关联+快速失败
当A关联资源/testB的qps的阈值超过1时,就限流/testA的Rest访问地址,
在这里插入图片描述
在postman模拟高并发请求
在这里插入图片描述
在这里插入图片描述
测试结果:
在这里插入图片描述
3、流控效果——Warm Up
Warm Up方式,即预热/冷启动方式。当系统长期处于低水位的情况下,当流量突然增加时,直接把系统拉升到高水位可能瞬间把系统压垮。通过“冷启动”,让通过的流量缓慢增加,在一定时间内逐渐增加到阈值上限,给冷系统一个预热的时间,避免冷系统被压垮。

默认coldFactor为3,即请求QPS从threshold / 3开始,经预热时长逐渐升至设定的QPS阈值。
在这里插入图片描述
案例:
阈值为10,预热时长设置5秒
系统初始化的阈值为10/3约等于3,即阈值刚开始为3,经过5秒后阈值慢慢恢复到10。
在这里插入图片描述
秒杀系统在开启的瞬间,会有很多流量进来,很有可能把系统打死,预热方式就是为了保护系统,可慢慢的把流量放进来,慢慢的把阈值增长到设置的阈值。

4、流控效果——排队等待
匀速排队,让请求以均匀的速度通过,阈值类型必须设置为QPS,否则无效。
案例:
设置含义,/testA每秒1次请求,超过则排队等待,等待的超时时间为20000毫秒,超时报错。
在这里插入图片描述
测试:
在这里插入图片描述
测试结果,可以看到1秒处理一个请求
在这里插入图片描述
该方式的作用如下图所示:
在这里插入图片描述
这种方式主要用于处理间隔性突发的流量,例如消息队列。例如,在某一秒有大量的请求到来,而接下来的几秒则处于空闲状态,我们希望系统能在接下来的空闲期间逐渐处理这些请求,而不是在第一秒直接拒绝多余的请求。

四、熔断降级

熔断降级会在调用链路中某个资源出现不稳定状态时(例如调用超时或异常比例升高),对这个资源的调用进行限制,让请求快速失败,避免影响到其它的资源而导致级联错误。没有半开状态。

半开状态:系统自动去检测是否请求有异常,没有异常就关闭断路器恢复使用,有异常则继续打开断路器不可用。

在这里插入图片描述

RT:平均响应时间,当 1s 内持续进入 N 个请求,对应时刻的平均响应时间(秒级)均超过阈值(count,以 ms 为单位),那么在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地熔断(抛出 DegradeException)。注意 Sentinel 默认统计的 RT 上限是 4900 ms,超出此阈值的都会算作 4900 ms,若需要变更此上限可以通过启动配置项 -Dcsp.sentinel.statistic.max.rt=xxx 来配置。

异常比例 (DEGRADE_GRADE_EXCEPTION_RATIO):当资源的每秒请求量 >= N(可配置),并且每秒异常总数占通过量的比值超过阈值(DegradeRule 中的 count)之后,资源进入降级状态,即在接下的时间窗口(DegradeRule 中的 timeWindow,以 s 为单位)之内,对这个方法的调用都会自动地返回。异常比率的阈值范围是 [0.0, 1.0],代表 0% - 100%。

异常数 (DEGRADE_GRADE_EXCEPTION_COUNT):当资源近 1 分钟的异常数目超过阈值之后会进行熔断。注意由于统计时间窗口是分钟级别的,若 timeWindow 小于 60s,则结束熔断状态后仍可能再进入熔断状态。

1、RT
在这里插入图片描述
Jmeter模拟压力测试,每秒10次,永远循环
在这里插入图片描述
在这里插入图片描述
结果:
在这里插入图片描述
如果 1s 内持续进了 N 个请求 且 平均响应时间均超过阈值,那么下一个窗口期服务熔断。本例中设置个请求 sleep 1s 所以,jmeter 每秒 10次(访问总次数)超过 n=5(默认是5),在下一个时间窗口期内服务熔断。

2、异常比例
在这里插入图片描述
默认请求量大于5时,异常比例占通过总量和的比例超过阈值时,进入降级状态,且下一个时间窗口期对这个方法调用自动返回。本例中异常比例为0.2,代码增加了异常,使用Jmeter模拟并发请求,Jmeter配置与RT的一样。

@GetMapping("/testD")
public String testD()
{
    log.info("testD 异常比例");
    int age = 10/0;
    return "------testD";
}

测试结果:
在这里插入图片描述
3、异常数
当资源近1分钟的异常数超过阈值之后会进行熔断。注意由于统计窗口是分钟级别的,若timewindow小于60s,则结束熔断状态后,仍可能再次进入熔断状态。
总结:时间窗口一定要大于等于60S
在这里插入图片描述
访问异常数超过5次后,将发生降级
在这里插入图片描述

五、热点规则

1、何为热点?
在这里插入图片描述
2、热点参数规则
在这里插入图片描述
3、controller

@GetMapping("/testHotKey")
//名字可以随意起,但为唯一标识
@SentinelResource(value = "testHotKey",blockHandler = "deal_testHotKey")
public String testHotKey(@RequestParam(value = "p1",required = false) String p1,
                         @RequestParam(value = "p2",required = false) String p2)
{
    //int age = 10/0;
    return "------testHotKey";
}
public String deal_testHotKey (String p1, String p2, BlockException exception)
{
    return "------deal_testHotKey,o(╥﹏╥)o";  //sentinel系统默认的提示:Blocked by Sentinel (flow limiting)
}

4、热点规则
blockHandler:回调方法
在这里插入图片描述
5、测试
携带第一个参数p1,访问超过阈值1后,将发生降级
在这里插入图片描述
当没有配置回调方法blockHandler,降级后的页面如下,对用户是非常不友好的
在这里插入图片描述
6、参数例外项
在这里插入图片描述
其中,参数类型为Java中对应的参数类型,本例中p1等于5时,访问超过阈值后,不会发生降级
注意:@SentinelResource中blockHandler参数处理的是Sentinel控制台配置的违规情况,而RuntimeException是Java运行时的异常,不属于@SentinelResource管辖。

7、问题
上述blockHandler中兜底方案面临的问题:

  • 系统默认的,没有体现我们自己的业务要求
  • 依照现有条件,我们自定义的处理方法和业务代码耦合,不直观
  • 每个业务方法都添加一个兜底的方法,会使代码膨胀加剧
  • 全局统一的处理方法没有体现

8、解决办法
自定义异常处理类,实现与业务代码解耦
CustomerBlockHandler

public class CustomerBlockHandler
{
    public static CommonResult handlerException(BlockException exception)
    {
        return new CommonResult(4444,"按客戶自定义,global handlerException----1");
    }
    public static CommonResult handlerException2(BlockException exception)
    {
        return new CommonResult(4444,"按客戶自定义,global handlerException----2");
    }
}

在Controller的业务方法中,指定处理异常的方法
在这里插入图片描述
测试:
在这里插入图片描述
9、@SentinelResource的fallback参数
fallback用来处理Java的异常。当fallback和blockHandler同时配置时,优先使用blockHandler。

六、系统自适应限流

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

2、能做什么

  • 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 达到阈值即触发系统保护。

总结:就是对整个系统添加限流,不推荐使用

七、持久化

通过Nacos做持久化操作

pom

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

yml

spring:
  cloud:
    sentinel:
      datasource:
        ds1:
          nacos:
            server-addr: localhost:8848 #nacos地址
            dataId: cloud-alibaba-sentinel-service  #微服务名称,与nacos的DataId对应
            groupId: DEFAULT_GROUP  #默认分组
            data-type: json #数据格式
            rule-type: flow #流控规则

nocos 8848 中新增配置
在这里插入图片描述
resource:资源名称
limitApp:来源应用
grade:1,//阈值类型,0线程数,1QPS
count:1,//单机阈值
strategy:0,//流控模式,0表示直接,1表示关联,2表示链路
controlBehavior:0,//流控效果 ,0表示快速失败,1表示warm up,2表示排队等待
clusterMode:false //是否集群

测试
重启8401,访问http://localhost:8401/rateLimit/byUrl,即可看到sentinel中出现了相应的流控规则
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值