当前位置: 代码迷 >> 综合 >> Spring Cloud Alibaba 之 Sentinel
  详细解决方案

Spring Cloud Alibaba 之 Sentinel

热度:7   发布时间:2023-12-08 06:58:26.0

文章目录

  • Sentinel简介
  • 核心代码
    • 依赖
    • 核心配置
  • 流控规则解析
  • 熔断降级
    • 慢调用比例RT (SLOW_REQUEST_RATIO)
    • 异常比例 (ERROR_RATIO)
    • 异常数 (ERROR_COUNT)
  • 热点key的流控
    • 测试代码
    • 配置热点参数的阈值
    • 参数例外项
  • 系统保护规则(整体维度)
  • @SentinelResource使用
    • value属性
    • BlockHandler属性
    • blockHandlerClass属性
    • exceptionsToIgnore属性
    • fallback属性
  • 自定义降级处理类(可以代码解耦)
  • 整合OpenFeign
  • 规则的持久化配置
  • 熔断降级框架对比
  • 参考

Spring Cloud 系列笔记

Sentinel简介

  • 是一个轻量级的流量控制、熔断降级 Java 库

  • 主要特性如下:
    在这里插入图片描述

  • Sentinel 组件由 2 部分组成

    • 核心库(Java客户端):不依赖任何框架/库,能够运行于所有Java运行时环境,同时对 Dubbo /Spring Cloud等框架也有较好的支持。
    • 控制台(Dashboard):基于Spring Boot 开发,打包后可以直接运行,不需要额外的Tomcat等应用容器。
  • 下载后执行 java -jar sentinel-dashboard-x.x.x.jar,然后访问本地8080端口即可,默认账号密码是sentinel

核心代码

依赖

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

核心配置

spring:application:name: cloudalibaba-sentinel-servicecloud:nacos:discovery:server-addr: localhost:8848sentinel:transport:dashboard: localhost:8080port: 8719  #默认8719,假如被占用了会自动从8719开始依次+1扫描。直至找到未被占用的端口
  • 启动项目后需要访问某个接口(懒加载)才能在sentinel界面看到监控数据

流控规则解析

在这里插入图片描述

  • 资源名:唯一,默认请求路径(如:http://localhost:port/testA)
  • 针对来源:Sentinel可以针对调用者进行限流,填写微服务名,指定对哪个微服务进行限流 ,默认default(不区分来源,全部限制)
  • 阈值类型/单机阈值:
    • 1、QPS(每秒钟的请求数量):当调用该接口的QPS达到了阈值的时候,进行限流;
    • 2、线程数:当调用该接口的线程数达到阈值时,进行限流
    • 线程数代表的是每秒内访问api接口的线程数,如果该接口的操作比较长,当排队的线程数到达阈值的时候,进行限流操作,相反的如果接口的操作很快,即是没秒内的操作很快,同样不会进行限流操作。QPS可以简单的理解为访问次数,但是线程数是和接口处理的快慢有关的。
  • 是否集群:不需要集群
  • 流控模式:
    • 1、直接:接口达到限流条件时,直接限流
    • 2、关联:当关联的资源达到阈值时,就限流自己(应用场景:支付接口达到阈值,就限流下订单的接口
    • 3、链路:只记录指定链路上的流量(指定资源从入口资源进来的流量,如果达到阈值,就可以限流)[api级别的针对来源]
  • 流控效果
    • 1、快速失败:直接失败
    • 2、Warm Up:即请求 QPS 从 最大阈值 / 3 (codeFactor,冷加载因子,默认为3)开始,经预热时长逐渐升至设定的阈值(应用场景:秒杀的瞬间,可能把系统打死,采用预热可以慢慢放流量进来,阈值不是一开始就最大
    • 3、排队等待(类似于漏桶算法)(应用场景:处理间隔性突发流量,例如消息队列)

熔断降级

  • 注意熔断和流控的区别,熔断是接口直接不可用了

在这里插入图片描述

慢调用比例RT (SLOW_REQUEST_RATIO)

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

异常比例 (ERROR_RATIO)

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

异常数 (ERROR_COUNT)

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

热点key的流控

  • 热点即经常访问的数据。很多时候我们希望统计某个热点数据中访问频次最高的 Top K 数据,并对其访问进行限制。比如:
    • 商品 ID 为参数,统计一段时间内最常购买的商品 ID 并进行限制
    • 用户 ID 为参数,针对一段时间内频繁访问的用户 ID 进行限制

测试代码

@GetMapping("/testHotKey")
@SentinelResource(value = "testHotKey", blockHandler = "deal_testHotKey")
public String hotKeyTest(@RequestParam(value = "p1", required = false)String p1,@RequestParam(value = "p2", required = false)String p2){
    return "===== (*^_^*) 成功了 (*^_^*) =====";
}
public String deal_testHotKey(String p1, String p2, BlockException exception){
    return "===== (ㄒoㄒ) 失败了 (ㄒoㄒ) =====";
}

配置热点参数的阈值

在这里插入图片描述

  • 发出请求并带上 p1 参数,访问 :http://localhost:8401/testHotKey?p1=aaa
  • 如果 1 秒点一下,可以正常访问,但是 1 秒内,连续请求,就会走备选方案
  • 注意资源名也可以是url地址哦

参数例外项

  • 上述情况,不论被监控的参数传入的是何值,都会进行判断,并限流
  • 但是有些时候有些特殊值,希望它的阈值和其他不一样,就要使用该配置
  • 比如说:p1 传入 aaa 时的阈值可以允许达到 100,但是其他值只能达到 10

在这里插入图片描述

系统保护规则(整体维度)

在这里插入图片描述

  • 简单来说,就是从整体维度对入口进行流控
  • 名词解释:
    • 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使用

  • 该注解用于配合sentinel控制台进行流控、熔断降级等操作,通过它可以指定自定义的降级策略,而不是阿里的直接返回一个blockException
@RequestMapping("/consumer/fallback/{id}")
@SentinelResource(value = "fallback",fallback = "handlerFallback",blockHandler = "blockHandler",exceptionsToIgnore = {
    IllegalArgumentException.class})
public CommonResult<Payment> fallback(@PathVariable Long id)
{
    CommonResult<Payment> result = restTemplate.getForObject(SERVICE_URL + "/paymentSQL/"+id,CommonResult.class,id);if (id == 4) {
    throw new IllegalArgumentException ("IllegalArgumentException,非法参数异常....");}else if (result.getData() == null) {
    throw new NullPointerException ("NullPointerException,该ID没有对应记录,空指针异常");}return result;
}
//本例是fallback
public CommonResult handlerFallback(@PathVariable  Long id,Throwable e) {
    Payment payment = new Payment(id,"null");return new CommonResult<>(444,"兜底异常handlerFallback,exception内容 "+e.getMessage(),payment);
}
//本例是blockHandler
public CommonResult blockHandler(@PathVariable  Long id,BlockException blockException) {
    Payment payment = new Payment(id,"null");return new CommonResult<>(445,"blockHandler-sentinel限流,无此流水: blockException "+blockException.getMessage(),payment);
}

value属性

  • 资源名称,必填

BlockHandler属性

  • 处理BlockException的函数,该函数只负责sentinel控制台配置的违规
  • 注意:
    • 必须是 public
    • 返回类型与原方法一致
    • 参数类型需要和原方法相匹配,并在最后加 BlockException 类型的参数。
    • 默认需和原方法在同一个类中。若希望使用其他类的函数,可配置 blockHandlerClass ,并指定blockHandlerClass里面的方法。

blockHandlerClass属性

  • 存放blockHandler的类

exceptionsToIgnore属性

  • 指定忽略的异常,即对该异常不做任何处理

fallback属性

  • fallback 函数名称
  • 可选项,用于在接口抛出异常的时候提供 fallback 处理逻辑。fallback 函数可以针对所有类型的异常(除了 exceptionsToIgnore 里面排除掉的异常类型)进行处理。
  • fallback 函数签名和位置要求
    • 返回值类型必须与原函数返回值类型一致
    • 方法参数列表需要和原函数一致,或者可以额外多一个 Throwable 类型的参数用于接收对应的异常
    • fallback 函数默认需要和原方法在同一个类中。若希望使用其他类的函数,则可以指定 fallbackClass 为对应的类的 Class 对象,注意对应的函数必需为 static 函数,否则无法解析

自定义降级处理类(可以代码解耦)

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配置

@GetMapping("/rateLimit/customerBlockHandler")
@SentinelResource(value = "customerBlockHandler",blockHandlerClass = CustomerBlockHandler.class,blockHandler = "handlerException2")
public CommonResult customerBlockHandler()
{
    return new CommonResult(200,"按客戶自定义",new Payment(2020L,"serial003"));
}

整合OpenFeign

  • 这里采用的是一个消费者,两个服务提供者,消费者服务需要引入Feign的依赖
<dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
  • yaml要加一个配置:
feign:sentinel:enabled: true
  • 其他的关于feign的配置之前的文章有提到,这里就不说了

规则的持久化配置

  • 一旦我们重启应用,Sentinel规则将消失
  • 生产环境需要将配置规则进行持久化
  • 将限流配置规则持久化进 Nacos 保存

依赖

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

yaml

  • 配置持久化文件在nacos中的唯一标志等
datasource:ds1:nacos:server-addr: localhost:8848dataId: cloudalibaba-sentinel-servicegroupId: DEFAULT_GROUPdata-type: jsonrule-type: flow

在nacos配置列表中添加对应的配置文件

在这里插入图片描述

熔断降级框架对比

  • 可以看到Hystrix只支持降级保护,不支持限流

在这里插入图片描述

参考

SpringCloud-2.0-周阳(22. 流量监控 - Sentinel)学习笔记

SpringCloud-2.0-周阳(23. 熔断降级 - Sentinel)学习笔记

  相关解决方案