Sentinel

吴书松
吴书松
发布于 2025-05-08 / 12 阅读
1

Sentinel

1、springboot整合

1、导入依赖

注意,低版本的sentinel和高版本的springboot是不兼容的,会导致sentinel无效

<!-- sentinel -->
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-core</artifactId>
   <version>1.8.6</version>
</dependency>
<!-- 当前依赖,熔断使用 -->
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-annotation-aspectj</artifactId>
   <version>1.8.6</version>
</dependency>
<!-- Sentinel本地应用接入控制台如果不接入控制台,可以不导入 -->
<dependency>
   <groupId>com.alibaba.csp</groupId>
   <artifactId>sentinel-transport-simple-http</artifactId>
   <version>1.8.6</version>
</dependency>

微服务添加依赖

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

2、添加配置

启动类中,注入SentinelResourceAspect对象,否则 SentinelResource.blockHandler (限流降级处理) 不生效

    @Bean
    @ConditionalOnMissingBean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

3、使用

注意,sentinel中,”资源“ 就相当于 标签 的含义

被”资源“(标签) 修饰的 接口/方法,是被资源的规则所限制

资源的规则是可以手动配置(硬编码)的,也可以通过sentinel控制台动态配置

1、方式1:手动配置资源

设置一个资源名称为 sentinel_hello,表明当前接口/方法 被资源sentinel_hello的规则限制

Entry ignored = SphU.entry("sentinel_hello");

2、方式2:注解方式配置资源

@SentinelResource(value = "sentinel_hello_v3",blockHandler = "helloV2Handler",fallback = "helloV3Hystrix",fallbackClass = TestController.class)Copy to clipboardErrorCopied
注解含义:
value = "sentinel_hello_v3"    # 资源名称:sentinel_hello_v3
blockHandler = "helloV2Handler"    #限流被触发之后,降级调用的方法 方法名是:helloV2Handler,如果不在同一个类中,需要是静态的static
        1、参数需要与资源接口保持一致,可以而外多一个参数:BlockException ex
        2、需要和资源接口在同一个类中        
blockHandlerClass = TestController.class        #限流被触发之后,降级调用的方法所在的类,如果再同一个类中,可以不用设置
fallback = "helloV3Hystrix"    #熔断(异常)被触发之后,降级调用的方法 方法名是:helloV3Hystrix,如果不在同一个类中,需要是静态的static
        1、参数需要与资源接口保持一致,可以而外多一个参数:Throwable ex
        2、如果没有指定参数4,需要根资源接口处于同一个类
fallbackClass = TestController.class        #限流/熔断触发之后,降级调用的方法所在的类,如果再同一个类中,可以不用设置
entryType = EntryType.IN/OUT 资源流程方向,controller接口采用IN

4、资源规则配置

1、硬编码配置:手动再代码中写死配置

使用@PostConstruct注解,再本类构造方法执行结束后执行

@PostConstruct
public void initFlowRule() {
    /* 1.创建存放限流规则的集合 */
    List<FlowRule> rules = new ArrayList<>();
    /* 2.创建限流规则 */
    FlowRule rule = new FlowRule();
    /* 定义资源,表示 Sentinel 会对哪个资源生效 */
    rule.setResource("sentinel_hello");
    /* 定义限流的类型(此处使用 QPS 作为限流类型) */
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    /* 定义 QPS 每秒通过的请求数 */
    rule.setCount(2);
    /* 3.将限流规则存放到集合中 */
    rules.add(rule);

    /* 2.创建限流规则 */
    FlowRule rule2 = new FlowRule();
    /* 定义资源,表示 Sentinel 会对哪个资源生效 */
    rule2.setResource("sentinel_hello_v2");
    /* 定义限流的类型(此处使用 QPS 作为限流类型) */
    rule2.setGrade(RuleConstant.FLOW_GRADE_QPS);
    /* 定义 QPS 每秒通过的请求数 */
    rule2.setCount(2);
    /* 3.将限流规则存放到集合中 */
    rules.add(rule2);


    /* 2.创建限流规则 */
    FlowRule rule3 = new FlowRule();
    /* 定义资源,表示 Sentinel 会对哪个资源生效 */
    rule3.setResource("sentinel_hello_v3");
    /* 定义限流的类型(此处使用 QPS 作为限流类型) */
    rule3.setGrade(RuleConstant.FLOW_GRADE_QPS);
    /* 定义 QPS 每秒通过的请求数 */
    rule3.setCount(2);
    /* 3.将限流规则存放到集合中 */
    rules.add(rule3);

    /* 4.加载限流规则 */
    FlowRuleManager.loadRules(rules);
}

2、sentinel控制台动态配置

当前方式,需要搭建sentinel控制台服务

1、下载sentinel控制台jar包

https://github.com/alibaba/Sentinel/releases

2、启动 Sentinel 控制台

java -Dserver.port=8092 -jar sentinel-dashboard-1.8.0.jar
#!/bin/bash

# 定义变量
APP_NAME="cloud-sentinel"
JAR_FILE="/usr/local/java/cloud/sentinel/sentinel-dashboard-1.8.4.jar"
PID_FILE="app.pid"

# 启动方法
start() {
  echo "Starting $APP_NAME ..."
  nohup java -jar $JAR_FILE --server.port=8092 > ./console.log 2>&1 &
  echo $! > $PID_FILE
  echo "$APP_NAME started successfully."
}

# 重启方法
restart() {
  stop
  start
}

# 停止方法
stop() {
  if [ -f $PID_FILE ]; then
    PID=$(cat $PID_FILE)
    echo "Stopping $APP_NAME ..."
    kill $PID
    rm $PID_FILE
    echo "$APP_NAME stopped."
  else
    echo "$APP_NAME is not running."
  fi
}

# 根据命令行参数执行相应操作
case "$1" in
  start)
    start
    ;;
  restart)
    restart
    ;;
  stop)
    stop
    ;;
  *)
    echo "Usage: $0 {start|restart|stop}"
    exit 1
esac

3、访问 Sentinel 控制台:http://127.0.0.1:8092/

账号和密码都是:sentinel

4、项目整合控制台

控制台启动成功了,但是还没有和项目整合

1、springboot项目增加配置
-Dcsp.sentinel.dashboard.server=localhost:8092 -Dproject.name=Sentinel-Quick-Start

2、微服务增加配置
spring: 
  cloud:
    sentinel:
      eager: true
      transport:
        dashboard: jm-cloud-sentinel:8092
3、启动项目,链接控制台

项目启动之后,第一次进入控制台是不会链接上的,需要访问下受限制的接口,才能自动链接

访问接口:http://jm-cloud-gateway:23500/iotbase/iotPackageDataInfo/test

该接口必须要添加了注解@SentinelResource的接口

4、添加规则

对应号资源名称

测试

sentinel 控制台模式,配置添加规则之后,服务重启规则丢失解决方案

1、配置加载到nacos,采用配置管理的json格式做配置

1、依赖/配置

1、nacos服务注册/配置依赖

        <!--必备: 注册中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>2021.0.6.0</version>
        </dependency>
        <!--必备: 配置中心客户端-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
            <version>2021.0.6.0</version>
        </dependency>

yml配置

  cloud:
    nacos:
      username: jm-server
      password: jm-inner-0311.
      discovery:
        server-addr: 192.168.1.111:8848
        namespace: jm-cloud-dev
        group: DEFAULT_GROUP
      config:
        server-addr: 192.168.1.111:8848
        namespace: jm-cloud-dev
        group: DEFAULT_GROUP
  config:
    import:
      - nacos:springboot-sentinel.yml

2、nacos-datasource

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

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

yml配置


  cloud:
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8092
        heartbeat-interval-ms: 500
      datasource:
        dsl:
          nacos:
            username: jm-server
            password: jm-inner-0311.
            server-addr: 192.168.1.111:8848
            dataId: springboot-sentinel
            groupId: DEFAULT_GROUP
            namespace: jm-cloud-dev
            data_type: json
            rule-type: flow
Copy to clipboardErrorCopied

完整配置

server:
  port: 9004
spring:
  application:
    name: springboot-sentinel

  cloud:
    nacos:
      username: jm-server
      password: jm-inner-0311.
      discovery:
        server-addr: 192.168.1.111:8848
        namespace: jm-cloud-dev
        group: DEFAULT_GROUP
      config:
        server-addr: 192.168.1.111:8848
        namespace: jm-cloud-dev
        group: DEFAULT_GROUP
    sentinel:
      transport:
        #配置Sentinel dashboard地址
        dashboard: localhost:8092
      datasource:
        dsl:
          nacos:
            username: jm-server
            password: jm-inner-0311.
            server-addr: 192.168.1.111:8848
            dataId: springboot-sentinel
            groupId: DEFAULT_GROUP
            namespace: jm-cloud-dev
            data_type: json
            rule-type: flow
  config:
    import:
      - nacos:springboot-sentinel.yml


Copy to clipboardErrorCopied

nacos中添加配置:springboot-sentinel

该配置就是sentinel的规则配置,后期所有的限流规则配置都再这里配置

[
    {
        "resource": "sentinel_hello_v4",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "clusterMode": false,
        "controlBehavior": 0,
        "strategy": 0,
        "warmUpPeriodSec": 10,
        "maxQueueingTimeMs": 500,
        "refResource": "rrr"
    },
     {
        "resource": "sentinel_hello_v2",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "clusterMode": false,
        "controlBehavior": 0,
        "strategy": 0,
        "warmUpPeriodSec": 10,
        "maxQueueingTimeMs": 500,
        "refResource": "rrr"
    }
]

含义:

  • resource: 资源名称

  • limitApp: 流控的所属应用

  • grade: 流控模式,0-线程数模式,1-QPS

  • count:单机的限流阈值

  • strategy:流控模式,0-直连,1-关联,2-链路

  • controlBehavior:流控模式,0-快速失败,1-warm up(),2-排队等待

  • clusterMode:是否集群。true/false

nacos中各种json配置

流控规则

[
  {
    // 资源名
    "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": "sentinel_spring_web_context",
      // 流控应用
    "limitApp": "/test",
    // 授权类型(0代表白名单;1代表黑名单。)
    "strategy": 0
  }
]

本地文件存储

依赖按照上面添加即可

1、创建配置类

package com.wss.springbootsentinel.controller.config;

import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.*;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.List;

//@Component
public class SentinelPerFile implements InitFunc {

    @Value("spring.application.name")
    private String applicationName;
    @Override
    public void init() throws Exception {
        String ruleDir = System.getProperty("user.home") + "/sentinel/rules/"+applicationName;
        String flowRulePath = ruleDir + "/flow-rule.json";
        String degradeRulePath = ruleDir + "/degrade-rule.json";
        String systemRulePath = ruleDir + "/system-rule.json";
        String authorityRulePath = ruleDir + "/authority-rule.json";
        String paramFlowRulePath = ruleDir + "/param-flow-rule.json";

        this.mkdirIfNotExits(ruleDir);
        this.createFileIfNotExits(flowRulePath);
        this.createFileIfNotExits(degradeRulePath);
        this.createFileIfNotExits(systemRulePath);
        this.createFileIfNotExits(authorityRulePath);
        this.createFileIfNotExits(paramFlowRulePath);

        // 注册一个可读数据源,用来定时读取本地的json文件,更新到规则缓存中
        // 流控规则
        ReadableDataSource<String, List<FlowRule>> flowRuleRDS =
                new FileRefreshableDataSource<>(flowRulePath, flowRuleListParser);
        // 将可读数据源注册至FlowRuleManager
        // 这样当规则文件发生变化时,就会更新规则到内存
        FlowRuleManager.register2Property(flowRuleRDS.getProperty());
        WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<>(
                flowRulePath,
                this::encodeJson
        );
        // 将可写数据源注册至transport模块的WritableDataSourceRegistry中
        // 这样收到控制台推送的规则时,Sentinel会先更新到内存,然后将规则写入到文件中
        WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);

        // 降级规则
        ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(
                degradeRulePath,
                degradeRuleListParser
        );
        DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
        WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(
                degradeRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);

        // 系统规则
        ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(
                systemRulePath,
                systemRuleListParser
        );
        SystemRuleManager.register2Property(systemRuleRDS.getProperty());
        WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(
                systemRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);

        // 授权规则
        ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(
                authorityRulePath,
                authorityRuleListParser
        );
        AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
        WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(
                authorityRulePath,
                this::encodeJson
        );
        WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);

        // 热点参数规则
        ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
                paramFlowRulePath,
                paramFlowRuleListParser
        );
        ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
        WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(
                paramFlowRulePath,
                this::encodeJson
        );
        ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
    }

    private Converter<String, List<FlowRule>> flowRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<FlowRule>>() {
            }
    );
    private Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<DegradeRule>>() {
            }
    );
    private Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<SystemRule>>() {
            }
    );

    private Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<AuthorityRule>>() {
            }
    );

    private Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON.parseObject(
            source,
            new TypeReference<List<ParamFlowRule>>() {
            }
    );

    private void mkdirIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.mkdirs();
        }
    }

    private void createFileIfNotExits(String filePath) throws IOException {
        File file = new File(filePath);
        if (!file.exists()) {
            file.createNewFile();
        }
    }

    private <T> String encodeJson(T t) {
        return JSON.toJSONString(t);
    }

}

再resources中创建文件

1、创建目录1:META-INF

2、创建目录2:services

3、创建文件:com.alibaba.csp.sentinel.init.InitFunc

4、添加内容:SentinelPerFile类的全类名

完成配置

再SentinelPerFile中指定的路径下,创建配置文件即可