Sentinel组件使用

Sentinel环境搭建

通过Github下载对应的Jar包,下载地址

java -jar sentinel-dashboard-1.8.4.jar
启动参数配置(命令行模式)

-Dserver.port=8001 修改启动端口

-Dsentinel.dashboard.auth.username=sentinel 修改控制台登陆用户名

sentinel.dashboard.auth.password=sentinel 修改控制台登陆密码

剩下的配置可以参考官方的配置: 官方配置信息

在1.7.0版本之后还可以使用配置文件的形式来指定,但是我没实现成功


限流规则

流控限流规则

阈值类型分类

  • QPS:单位时间内的请求数量
  • 并发线程数:单位时间内的访问线程数量

流控模式分类

  • 直接:针对于当前接口
  • 关联:A关联B,当B达到限流后A触发限流规则
  • 链路:

流控效果分类

  • 快速失败:达到限流规则后后面在来的请求直接执行对应的限流策略
  • WarmUp(预热):启动因子默认为3,即QPS为3,当达到这个阈值后在设置的时间窗口期内逐渐放大请求量到设置的最大阈值
  • 排队等待:达到最大的访问阈值后,进行排队等待,直到等待时间超过设置的超时时间时执行对应的限流处理逻辑
熔断限流规则

熔断策略分类

  • 慢调用比例:单位时间内的请求数超过设置的调用时间的比例在总的请求数中达到一定的比例则触发限流规则,那么在指定的熔断时间内,该接口后续的请求都会直接触发熔断逻辑
  • 异常比例:单位时间内触发的异常占到了一定的比例,则触发熔断规则,后续的请求在设置的熔断时间窗口期内都将直接触发熔断逻辑
  • 异常数:单位时间内发生异常的次数为设置的次数时,触发熔断规则,后续的请求在设置的熔断窗口期内都将直接触发熔断逻辑
热点限流规则

对请求的接口中的某个请求参数进行限流,当单位时间内的QPS超过阈值时进行限流

参数例外项:前面说的是对请求参数进行限流,也就是不管你的请求参数的值是什么都会触发,但是参数例外项则是设置当请求参数为某个值是则触发的QPS条件为设置的阈值

系统限流规则

前面所说的限流规则都是单独针对服务中的某个具体的请求的,如果很多接口不可能每个都这么配置,所以出现了系统规则的限流方案

系统限流规则模式分类

  • Load自适应(仅对Linux/Unix-like机器生效):系统的load作为启发指标,进行自适应系统保护,当系统的loadl1超过设定的触发值,且系统当前的并发线程数超过估算的系统容量时才会触发系统保护。
  • CPU使用率:当系统的CPU使用率超过阈值时触发限流规则
  • 平均RT(平均调用时间):当单台机器上所有入口流量的平均RT时间达到阈值时触发限流规则
  • 并发线程数:当单台机器上所有入口流量的并发线程数达到阈值时触发
  • 入口QPS:当单台机器上所有入口流量的QPS达到阈值时触发

基本使用

使用代码的方式演示官网中所有的限流规则配置极其使用,并通过测试的方式直观呈现各限流规则的体现

引入依赖
<dependencies>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-webartifactId>
    dependency>
    <dependency>
        <groupId>org.springframework.bootgroupId>
        <artifactId>spring-boot-starter-actuatorartifactId>
    dependency>
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
    dependency>
    
    <dependency>
        <groupId>com.alibaba.cloudgroupId>
        <artifactId>spring-cloud-starter-alibaba-sentinelartifactId>
    dependency>
dependencies>
修改配置文件
server:
  port: 8001

spring:
  application:
    name: sentinel-provider
  cloud:
    nacos:
      discovery:
        server-addr: http://192.168.72.130:8848
    sentinel:
      transport:
        port: 8719
        dashboard: http://192.168.72.130:8080
management:
  endpoints:
    web:
      exposure:
        include: "*"
主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelProvider8001 {
    public static void main(String[] args){
        SpringApplication.run(SentinelProvider8001.class,args);
    }
}
热点限流规则实现及其测试

sentinel控制台中有很多的限流规则,不一一实现了,这里实现一个比较特特殊的就是热点规则限流,它是根据请求参数中的某个具体的参数进行限流的,例如在请求中出现了A参数那么就执行我们配置的限流规则,同时也提供了特殊处理,比如如果A等于5的话就不执行设置的限流规则,控制台相关配置如下

Sentinel组件使用_第1张图片

测试接口编写

@RestController
public class TestController {
    @GetMapping("/hotkey")
    //p1就是我们在控制太配置的需要限流的热点参数
    public String hotKey(@RequestParam(value = "p1", required = false) String p1,
                         @RequestParam(value = "p2", required = false) String p2) {
        return "正常使用热点建规则";
    }
}

分别测试接口:http://localhost:8001?p1=1&p2=10 因为设置的QPS是1所以点的快点就可以看到流控效果,在测试设置特殊热点是否不执行限流规则 http://localhost:8001?p1=5&p2=10


@SentinelResource

限流
  • 资源名称进行限流:控制要跟据代码中使用SentinelResource注解时使用的资源名称进行限流

  • 地址限流:控制台限流规则配置跟据请求地址进行限流

单个方法的限流处理方案实现

需要在Sentinel控制台中新增对于testResource资源的限流规则下面的方案同理的也需要在Sentinel中新增对该资源的限流规则

@RestController
public class TestController{
    @GetMapping("/test")
    @SentinelResource(value="testResource",blockHandler="testBlockHandler")
    public String test(){
        return "test1";
    }
    
    //和原方法所需的参数以及返回值一致,可以额外加一个参数类型为BlockException
    public String testBlockHandler(){
        return "使用单个方法的限流处理";
    }
}
外部类限流处理方案实现
@RestController
public class TestController{
    @GetMapping("/test")
    @SentinelResource(
        value="testResource",
        blockHandlerClass = CustomBlockHandler.class,
        blockHandler = "blockHandler")
    public String test(){
        return "test1";
    }
}


@Component
public class CustomBlockHandler{
    public static String blockHandler(){
        return "使用外部类的限流处理方案";
    }
}

在使用外部类中的方法作为限流方案时对应的限流处理方法需要声明为静态方法

全局限流处理方案实现

在上面的配置中限流都是针对于某个具体的接口使用@SentinelResource注解实现的,但是在使用nacos进行持久化限流规则选用系统限流配置时发现单个方法这样的配置不能够触发自定义的限流处理方案,并且如果需要进行限流的接口比较多时不可能每个都去这么使用@SentinelResource注解进行限流,回归本质问题,在没有设置自定义限流处理逻辑时也会触发默认的处理方法,只不过是Sentinel自己抛出的一个异常,DefaultBlockExceptionHandler这个类中就是Sentinel自带的限流处理逻辑,仿照这个类就可以实现自定义的全局限流方案

@Configuration
public class SentinelConfig implements BlockExceptionHandler {
    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws Exception {
        httpServletResponse.setContentType("text/json;charset=utf-8");
        httpServletResponse.getWriter().write("使用配置类配置的自定义限流处理逻辑");
    }
}

注意:如果同时配置了全局限流处理逻辑和单个方法的限流方法,那么方法就不会在使用全局的了,而是使用自己单独配置的限流处理逻辑

降级
单个方法降级处理方案实现
@RestControlelr
public class TestController{
    
    @GetMapping("/test")
    @SentinelResource(value="testFallback",fallbackHandler="testFallbackHandler")
    public String test(){
        //故意抛出错误进行降级处理
        int i=10/0;
        return "test1"
    }
    
    //方法的参数列表和返回值和需要降级的方法一致,可以额外多一个类型类型为Throwable的参数
    public String testFallbackHandler(){
       	return "当个方法的降级处理策略";
    }
}

fallback和defaultFallback的区别:fallback指定的降级处理方法的参数列表和返回值需要和原方法一致,defaultFallback指定的方法参数列表必须为空,并且方法的返回值必须和原方法一致,如果同时设置了fallback属性和defaultFallback属性则触发降级时会选用fallback属性指定的方法

外部类降级处理方案实现
@RestControlelr
public class TestController{
    
    @GetMapping("/test")
    @SentinelResource(value="testFallback",fallbackClass=CustomFallback.class,fallbackHandler="fallbackHandler")
    public String test(){
        //故意抛出错误进行降级处理
        int i=10/0;
        return "test1"
    }
}

@Component
public class CustomFallback{
    //该方法必须声明为静态方法
    public static String fallbackHandler{
        return "使用外部自定义降级处理方法";
    }
}
全局统一降级处理方案实现

**限流和降级的区别:**限流是针对于在Sentinel面板中配置的限流规则的,即达到了面板中设置的规则时进行触发,降级是在程序运行过程中触发的兜底策略,例如程序运行异常之类的。两者之间是可以同时配置的,不会有冲突

限流和降级都是针对于@SentinelResource注解进行展开的具体详细的配置流程可以参照官网给出的解释:@SentinelResource官网详细解释

失效场景

1.限流规则失效场景


限流规则持久化

在Sentinel控制台中配置的限流规则在应用重启后就会消失,可以结合Nacos对限流规则进行相应的限流

引入相关依赖,除了基本的seninel的依赖之外还需要引入一个额外的,这里使用nacos来进行规则持久化配置,如果不使用nacos的话就看官网使用其他方式进行实现实现,这里不做赘述


<dependency>
  <groupId>com.alibaba.cspgroupId>
  <artifactId>sentinel-datasource-nacosartifactId>
dependency>

修改配置文件

spring:
application:
name: sentinel-provider
cloud:
sentinel:
transport:
  port: 8719
  dashboard: http://192.168.72.130:8080
  #获取nacos上的限流规则
datasource:
  flow: #限流规则名称(随意)
    nacos: #使用nacos进行规则持久化
      username: nacos #nacos访问用户名
      password: nacos #nacos访问密码
      server-addr: http://192.168.72.130:8848 #nacos地址
      data-type: json #nacos配置文件类型
      data-id: ${spring.application.name}-sentinel-flow #nacos中限流配置文件的dataID
      group-id: DEFAULT_GROUP #nacos中限流规则的分组\
      namespace: d7de7037-c6db-4c03-a11c-1b77f166c952
      rule-type: flow #限流规则,还有其他的限流规则方式分别是

然后就可以尽情使用了

流控限流规则配置文件
[
 {
       // 资源名
       "resource": "/test",
       // 针对来源,若为 default 则不区分调用来源
       "limitApp": "default",
       // 限流阈值类型(1:QPS;0:并发线程数)
       "grade": 1,
       // 阈值
       "count": 1,
       // 是否是集群模式
       "clusterMode": false,
       // 流控效果(0:快速失败;1:Warm Up(预热模式);2:排队等待)
       "controlBehavior": 0,
       // 流控模式(0:直接;1:关联;2:链路)
       "strategy": 0,
       // 预热时间(秒,预热模式需要此参数)
       "warmUpPeriodSec": 10,
       // 超时时间(排队等待模式需要此参数)
       "maxQueueingTimeMs": 500,
       // 关联资源、入口资源(关联、链路模式)
       "refResource": "rrr"
 }
]
熔断限流规则配置文件
[
 {
     // 资源名
       "resource": "/test1",
       "limitApp": "default",
       // 熔断策略(0:慢调用比例,1:异常比率,2:异常计数)
       "grade": 0,
       // 最大RT、比例阈值、异常数
       "count": 200,
       // 慢调用比例阈值,仅慢调用比例模式有效(1.8.0 引入)
       "slowRatioThreshold": 0.2,
       // 最小请求数
       "minRequestAmount": 5,
       // 当单位统计时长(类中默认1000)
       "statIntervalMs": 1000,
       // 熔断时长
       "timeWindow": 10
 }
]
热点规则限流配置文件
[
    {
        // 资源名
        "resource": "/test1",
        // 限流模式(QPS 模式,不可更改)
        "grade": 1,
        // 参数索引
        "paramIdx": 0,
        // 单机阈值
        "count": 13,
        // 统计窗口时长
        "durationInSec": 6,
        // 是否集群 默认false
        "clusterMode": 默认false,
        // 
        "burstCount": 0,
        // 集群模式配置
        "clusterConfig": {
            // 
            "fallbackToLocalWhenFail": true,
            // 
            "flowId": 2,
            // 
            "sampleCount": 10,
            // 
            "thresholdType": 0,
            // 
            "windowIntervalMs": 1000
        },
        // 流控效果(支持快速失败和匀速排队模式)
        "controlBehavior": 0,
        // 
        "limitApp": "default",
        // 
        "maxQueueingTimeMs": 0,
        // 高级选项
        "paramFlowItemList": [
            {
                // 参数类型
                "classType": "int",
                // 限流阈值
                "count": 222,
                // 参数值
                "object": "2"
            }
        ]
    }
]
系统限流规则配置文件
[
 {
     // RT
       "avgRt": 1,
       // CPU 使用率
       "highestCpuUsage": -1,
       // LOAD
       "highestSystemLoad": -1,
       // 线程数
       "maxThread": -1,
       // 入口 QPS
       "qps": -1
 }
]
授权限流规则配置文件
[
    {
        "resource": "/persistence/test1",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "clusterMode": false,
        "controlBehavior": 0,
        "strategy": 0
    },
    {
        // 资源名
        "resource": "/persistence/test2",
        // 限流模式(QPS 模式,不可更改)
        "grade": 1,
        // 参数索引
        "paramIdx": 1,
        // 单机阈值
        "count": 1,
        // 统计窗口时长
        "durationInSec": 1,
        // 是否集群 默认false
        "clusterMode": false,
        "burstCount": 0,

        "controlBehavior": 0,
        "limitApp": "default",
        "maxQueueingTimeMs": 0,
        "paramFlowItemList": [
            {
                // 参数类型
                "classType": "int",
                // 限流阈值
                "count": 10,
                // 参数值
                "object": "2"
            }
        ]
    }
]

限流规则动态刷新

前面配置的限流规则每当修改时就需要重启一下应用,官方也提供了动态刷新限流规则的配置。

新建配置类,实现ApplicationRunner接口主要就是想要在应用启动的时候就执行对应的程序,其余的方式不做赘述

这里不需要在客户端配置文件中写上获取限流规则的配置了,直接在这里获取就行了,配置文件中写好像是不能够支持动态刷新的

@Configuration
public class FlowRuleConfig implements ApplicationRunner {
//如果配合了使用从nacos中获取配曲的配置文件可以通过@NacosValue进行注入属性
//或则可以通过@configurationProperties注解从本地配置文件中进行获取
private String serverAddr="http://192.168.72.130:8848";

private String username="nacos";

private String password="nacos";

private String namespance="d7de7037-c6db-4c03-a11c-1b77f166c952";

private String groupId="DEFAULT_GROUP";

private String dataId="sentinel-provider-sentinel-flow";

@Override
public void run(ApplicationArguments args) throws Exception {
  //配置太多可以结合Properties类进行配置
  Properties properties=new Properties();
  properties.setProperty(PropertyKeyConst.SERVER_ADDR,serverAddr);
  properties.setProperty(PropertyKeyConst.USERNAME,username);
  properties.setProperty(PropertyKeyConst.PASSWORD,password);
  properties.setProperty(PropertyKeyConst.NAMESPACE,namespance);
  //官方写的核心代码就是这一段
  ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(properties, groupId, dataId,
          source -> JSON.parseObject(source, new TypeReference<>() {
          }));
  FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
}
}

上面的代码只是针对于使用流控规则的,如果一个持久化规则配置文件中有很多的不同的限流规则,那么就需要使用不同的规则管理器和规则类进行配置了,上面代码中的规则类和规则管理器分别就是FlowRuleFlowRuleManager,其他的规则类和管理器类都在com.alibaba.csp.sentinel.slots.block这个包下可以自行查看之后针对不同的限流规则使用不同的管理器进行注册。

配置文件中存在流控股则和系统规则时,配置类就是下面这种类型了

配置文件详情如下

[
  //流控规则
{
      "resource": "/persistence/test1",
      "limitApp": "default",
      "grade": 1,
      "count": 1,
      "clusterMode": false,
      "controlBehavior": 0,
      "strategy": 0
},
  //系统规则
{
      "qps":1
}
]
public void run(ApplicationArguments args) throws Exception {
  Properties properties=new Properties();
  properties.setProperty(PropertyKeyConst.SERVER_ADDR,serverAddr);
  properties.setProperty(PropertyKeyConst.USERNAME,username);
  properties.setProperty(PropertyKeyConst.PASSWORD,password);
  properties.setProperty(PropertyKeyConst.NAMESPACE,namespance);
//流控规则数据源配置
  ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(properties, groupId, dataId,
          source -> JSON.parseObject(source, new TypeReference<>() {
          }));

//系统规则数据源配置
  ReadableDataSource<String, List<SystemRule>> systemRuleDataSource = new NacosDataSource<>(properties, groupId, dataId,
          source -> JSON.parseObject(source, new TypeReference<>() {
          }));

//分别注册流控规则和系统规则,如果还有其他的自行衍生
  FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
  SystemRuleManager.register2Property(systemRuleDataSource.getProperty());

}

剩下的就跟限流规则持久化的配置一样了,在nacos中配置对应的限流规则即可

结合SpringGateway

sentinel版本要在1.6.0或以上,同时结合Nacos进行限流规则的持久化。这里只做网关的项目搭建,其他的服务就仅仅只是写了个接口并注册到nacos中而已没什么特殊操作

网关服务构建

自定义API分组哪个没实现,实现了之后在sentinel控制台中只看到了一个api分组的名字没有相应的匹配规则,debug看代码也是只获取到了名字而已不知道什么原因,但是配置就是这样,就不实现了。使用RouteID配置

1.引入依赖
<dependencies>
<dependency>
  <groupId>org.springframework.bootgroupId>
  <artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
  <groupId>org.springframework.bootgroupId>
  <artifactId>spring-boot-starter-actuatorartifactId>
dependency>
<dependency>
  <groupId>com.alibaba.cloudgroupId>
  <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
dependency>
dependencies>
2.配置文件编写
server:
port: 8003

spring:
application:
name: sentinel-gateway
cloud:
nacos:
discovery:
  server-addr: http://192.168.72.130:8848
  username: nacos
  password: nacos
  namespace: 26344dce-b8e5-4327-aa06-3ac40292cced
  group: DEFAULT_GROUP
sentinel:
transport:
  port: 8719
  dashboard: http://192.168.72.130:8080
  #自定义的限流响应值,也可以配置重定向页面这里使用配置文件的方式进行,当然也可以使用硬编码的方式,但是不推荐
scg:
  fallback:
    mode: response
    response-status: 200
    response-body: '{"code":502,"msg":"系统繁忙,请稍后再试!"}'
    #redirect: "/error"   #重定向到处理页面 
gateway:
#网关中的路由配置
routes:
      - id: service1
        uri: lb://gateway-service1
        predicates:
          - Path=/service1/**
        filters:
          - StripPrefix=1
      - id: service2
        uri: lb://gateway-service2
        predicates:
          - Path=/service2/**
        filters:
          - StripPrefix=1

#这个配置不是官方的配置是我自定义的,只是为了能够使用自动属性注入而已
sentinel:
gateway:
  rule:
    nacos:
      server-addr: http://192.168.72.130:8848
      username: nacos
      password: nacos
      namespace: 26344dce-b8e5-4327-aa06-3ac40292cced
      group-id: DEFAULT_GROUP
      route-data-id: gateway-flow-rule
      api-data-id: gateway-rule-api-group


3.编写配置类
@Configuration
@ConfigurationProperties(prefix = "sentinel.gateway.rule.nacos")
@Data
//实现ApplicationRunner注解使得程序启动就自动执行
public class SentinelGatewayLimitingConfig implements ApplicationRunner {
  private String serverAddr;

  private String username;

  private String password;

  private String namespace;

  private String groupId;

  private String routeDataId;

  private String apiDataId;


  public void loadLimitingRule(){
      Properties properties=new Properties();
      properties.setProperty(PropertyKeyConst.SERVER_ADDR,serverAddr);
      properties.setProperty(PropertyKeyConst.USERNAME,username);
      properties.setProperty(PropertyKeyConst.PASSWORD,password);
      properties.setProperty(PropertyKeyConst.NAMESPACE,namespace);

      //获取nacos中配置的限流规则
      ReadableDataSource<String, Set<GatewayFlowRule>> flowRule=new NacosDataSource<>(properties, groupId, routeDataId,
              source -> JSON.parseObject(source, new TypeReference<>() {
              }));

      //获取nacos中配置的api分组定义规则
      ReadableDataSource<String,Set<ApiDefinition>> apiDefinttion=new NacosDataSource<>(properties,groupId,apiDataId,
              source->JSON.parseObject(source,new TypeReference<>(){}));

      GatewayApiDefinitionManager.register2Property(apiDefinttion.getProperty());

      GatewayRuleManager.register2Property(flowRule.getProperty());
  }


  @Override
  public void run(ApplicationArguments args) throws Exception {
      loadLimitingRule();
  }
}
4.编写主启动类
@SpringBootApplication
@EnableDiscoveryClient
public class SentinelGateway8003 {
  public static void main(String[] args){
      SpringApplication.run(SentinelGateway8003.class,args);
  }
}
5.nacos编写持久化配置文件

配置文件的命名空间,group,以及dataId要和客户端配置文件中的一致

gateway-flow-rule文件主要是对限流规则的配置

[
  {
  "resource": "service1", //和前面的针对单独的资源限流的配置是一样的,不过这里的资源名称是routeID
  "resourceMode":0, //使用RouteId进行限流
  "limitApp": "default",
  "grade": 1,
  "count": 1,
  "clusterMode": false,
  "controlBehavior": 0,
  "strategy": 0
},{
  "resource":"serviceTest2", //这个是API分组名称
  "resourceMode":1, //使用自定义API分组进行限流
  "limitApp": "default",
  "grade": 1,
  "count": 1,
  "clusterMode": false,
  "controlBehavior": 0,
  "strategy": 0
}
]

gateway-rule-api-group主要是对自定义API分组的配置

[
{
  "apiName": "serviceTest2", //api分组名称
  "predicateItems": [
    {
      "matchStrategy": "1", //匹配规则从0-2,分别匹配的是控制台中的精确,前缀,正则
      "pattern": "/service2/**" //就是控制台中需要进行配置的字符串
    }
  ]
}
]
6.启动网关服务

在启动需要启动nacos和sentinel这里不做赘述但是网关客户端的启动需要添加额外的启动参数

-Dcsp.sentinel.app.type=1标记该应用是一个网关应用,可以在IDEA启动参数中配置

Sentinel组件使用_第2张图片

查看Sentinel控制台可以看到和之前的界面不太一样了

Sentinel组件使用_第3张图片

同时在点击流控规则时也可以看到在nacos配置的流控规则以及在Api管理中也可以看到在nacos中配置的api分组了

Sentinel组件使用_第4张图片

你可能感兴趣的:(SpringCloud,sentinel,java,前端)