Sentinel 配置持久化

规则参数

流控规则

配置

参数
Field 说明 默认值
resource 资源名,资源名是限流规则的作用对象
count 限流阈值
grade 限流阈值类型,QPS 或线程数模式 QPS 模式
limitApp 流控针对的调用来源 default,代表不区分调用来源
strategy 判断的根据是资源自身,还是根据其它关联资源 (refResource),还是根据链路入口 根据资源本身
controlBehavior 流控效果(直接拒绝 / 排队等待 / 慢启动模式) 直接拒绝
代码示例
1
2
3
4
5
6
7
8
9
10

private void initFlowQpsRule() {
    List<FlowRule> rules = new ArrayList<>();
    FlowRule rule = new FlowRule(resourceName);
    // set limit qps to 20
    rule.setCount(20);
    rule.setGrade(RuleConstant.FLOW_GRADE_QPS);
    rule.setLimitApp("default");
    rules.add(rule);
    FlowRuleManager.loadRules(rules);
}

降级规则

配置

参数
Field 说明 默认值
resource 资源名,即限流规则的作用对象
count 阈值
grade 降级模式,根据 RT 降级还是根据异常比例降级 RT
timeWindow 降级的时间,单位为 s
代码配置示例
1
2
3
4
5
6
7
8
9
10
11

private void initDegradeRule() {
    List<DegradeRule> rules = new ArrayList<>();
    DegradeRule rule = new DegradeRule();
    rule.setResource(KEY);
    // set threshold RT, 10 ms
    rule.setCount(10);
    rule.setGrade(RuleConstant.DEGRADE_GRADE_RT);
    rule.setTimeWindow(10);
    rules.add(rule);
    DegradeRuleManager.loadRules(rules);
}

热点规则

配置

参数
属性 说明 默认值
resource 资源名,必填
count 限流阈值,必填
grade 限流模式 QPS 模式
durationInSec 统计窗口时间长度(单位为秒),1.6.0 版本开始支持 1s
controlBehavior 流控效果(支持快速失败和匀速排队模式),1.6.0 版本开始支持 快速失败
maxQueueingTimeMs 最大排队等待时长(仅在匀速排队模式生效),1.6.0 版本开始支持 0ms
paramIdx 热点参数的索引,必填,对应 SphU.entry(xxx, args) 中的参数索引位置
paramFlowItemList 参数例外项,可以针对指定的参数值单独设置限流阈值,不受前面 count 阈值的限制。仅支持基本类型
clusterMode 是否是集群参数流控规则 false
clusterConfig 集群流控相关配置
代码配置示例
1
2
3
4
5
6
7
8
9
10

ParamFlowRule rule = new ParamFlowRule(resourceName)
    .setParamIdx(0)
    .setCount(5);
// 针对 int 类型的参数 PARAM_B,单独设置限流 QPS 阈值为 10,而不是全局的阈值 5.
ParamFlowItem item = new ParamFlowItem().setObject(String.valueOf(PARAM_B))
    .setClassType(int.class.getName())
    .setCount(10);
rule.setParamFlowItemList(Collections.singletonList(item));

ParamFlowRuleManager.loadRules(Collections.singletonList(rule));

系统规则

配置

参数
Field 说明 默认值
highestSystemLoad 最大的 load1 -1 (不生效)
avgRt 所有入口流量的平均响应时间 -1 (不生效)
maxThread 入口流量的最大并发数 -1 (不生效)
qps 所有入口资源的 QPS -1 (不生效)
代码配置示例
1
2
3
4
5
6
7

private void initSystemRule() {
    List<SystemRule> rules = new ArrayList<>();
    SystemRule rule = new SystemRule();
    rule.setHighestSystemLoad(10);
    rules.add(rule);
    SystemRuleManager.loadRules(rules);
}

授权规则

配置

参数
Field 说明 默认值
resource 资源名,即限流规则的作用对象
limitApp 对应的黑名单/白名单,不同 origin 用 , 分隔,如 appA,appB default,代表不区分调用来源
strategy 限制模式,AUTHORITY_WHITE 为白名单模式,AUTHORITY_BLACK 为黑名单模式,默认为白名单模式 AUTHORITY_WHITE

5.3 代码配置示例

1
2
3
4
5

AuthorityRule rule = new AuthorityRule();
rule.setResource("test");
rule.setStrategy(RuleConstant.AUTHORITY_WHITE);
rule.setLimitApp("appA,appB");
AuthorityRuleManager.loadRules(Collections.singletonList(rule));

概述

​ 前面我们介绍了sentinel控制台以及客户端的启动,并且实现了在控制台添加流控以及熔断规则,并且将规则发送给客户端。但是,将客户端重启,我们会发现,我们之前设置的规则将会丢失,这是因为客户端将规则保存在内存中,并没有将其持久化,因而,这样并不适用于生产环境。

Sentinel数据源

Sentinel的数据源可以通过多种方式加载:json、xml文件;zookeeper;apollo;nacos;并且可以多种数据源同时使用。

扩展方式

动态数据源:DataSource`扩展常见的实现方式

拉模式

​ 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件,甚至是 VCS 等。这样做的方式是简单,缺点是无法及时获取变更;

推模式

​ 规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。

原理简述

控制台推送规则:

  • 将规则推送到Nacos或其他远程配置中心
  • Sentinel客户端链接Nacos,获取规则配置;并监听Nacos配置变化,如发生变化,就更新本地缓存(从而让本地缓存总是和Nacos一致)
  • 控制台监听Nacos配置变化,如发生变化就更新本地缓存(从而让控制台本地缓存总是和Nacos一致)

要具体了解可以查看官网的介绍:动态规则扩展

在生产环境下推荐使用推模式, 这需要设置客户端,并且需要修改Sentinel控制台的源码

我们推荐通过控制台设置规则后将规则推送到统一的规则中心,客户端实现 ReadableDataSource 接口端监听规则中心实时获取变更,流程如下:

各个模式的对比

一般来说,规则的推送有下面三种模式:

推送模式 说明 优点 缺点
原始模式 API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource 简单,无任何依赖 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境
Pull 模式 扩展写数据源(WritableDataSource), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等 简单,无任何依赖;规则持久化 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。
Push 模式 扩展读数据源(ReadableDataSource),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。 规则持久化;一致性;快速 引入第三方依赖

限流规则推送Nacos

Sentinel客户端配置

引入POM依赖
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
    <version>2.2.1.RELEASE</version>
</dependency>
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <version>1.7.2</version>
</dependency>
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.70</version>
</dependency>
修改配置文件

默认sentinel控制台推送到nacos的dataId定义为: ${spring.application.name}-flow-rules

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

server.port=8083
# 配置中心url
spring.application.name=order-server
#注册中心地址
spring.cloud.nacos.server-addr=192.168.64.128:8848
#添加sentinel依赖后 暴露/actuator/sentinel端点
# 开启健康检查
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=ALWAYS
#打开/关闭掉对Spring MVC端点的保护
spring.cloud.sentinel.filter.enabled=false
#这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
spring.cloud.sentinel.transport.port=8731
#指定sentinel控制台的地址
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080

# 设置Sentinel Nacos数据源配置;其中ds是数据源名,可以自行随意修改
# Nacos数据源地址(需要启动一台Nacos Server)
# nacos 地址
spring.cloud.sentinel.datasource.ds.nacos.server-addr=${spring.cloud.nacos.server-addr}
spring.cloud.sentinel.datasource.ds.nacos.dataId=${spring.application.name}-flow-rules
spring.cloud.sentinel.datasource.ds.nacos.groupId=SENTINEL_GROUP
# 数据类型
spring.cloud.sentinel.datasource.ds3.nacos.data-type=json
# 规则类型
spring.cloud.sentinel.datasource.ds.nacos.rule-type=flow
添加Nacos数据源配置类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39

@Configuration
public class DataSourceInitFunc {

    Logger logger = LoggerFactory.getLogger(DataSourceInitFunc.class);

    @Autowired
    private SentinelProperties sentinelProperties;

    @Bean
    public DataSourceInitFunc init() throws Exception {

        logger.info("[NacosSource初始化,从Nacos中获取熔断规则]");

        sentinelProperties.getDatasource().entrySet().stream().filter(map -> {
            return map.getValue().getNacos() != null;
        }).forEach(map -> {
            NacosDataSourceProperties nacos = map.getValue().getNacos();
            // 限流规则,需要Nacos的dataId中包含flow字符串
            if (nacos.getDataId().contains("flow")) {
                ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new NacosDataSource<>(nacos.getServerAddr(),
                        nacos.getGroupId(), nacos.getDataId(),
                        source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
                        }));
                FlowRuleManager.register2Property(flowRuleDataSource.getProperty());
            }

            // 降级规则,需要Nacos的dataId中包含degrade字符串
            if (nacos.getDataId().contains("degrade")) {
                ReadableDataSource<String, List<DegradeRule>> degradeRuleDataSource = new NacosDataSource<>(nacos.getServerAddr(),
                        nacos.getGroupId(), nacos.getDataId(),
                        source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {
                        }));
                DegradeRuleManager.register2Property(degradeRuleDataSource.getProperty());
            }

        });
        return new DataSourceInitFunc();
    }
}
Nacos中添加熔断规则

根据配置文件配置的 id是 应用名-flow-rules

规则文件可以是json文件;也可以是text文件

规则是将 createOrder 的资源进行限流 使用QPS 模式 限流阈值 1

1
2
3
4
5
6
7
8
9
10
11

[
    {
        "resource": "createOrder",
        "limitApp": "default",
        "grade": 1,
        "count": 1,
        "strategy": 0,
        "controlBehavior": 0,
        "clusterMode": false
    }
]

具体参数参考 规则参数

测试

访问 http://localhost:8083/order/createorder/1 进行测试

这样会自动从配置中心读取配置信息不需要每次重启都需要配置了

控制台源码修改

​ 原始的客户端是将熔断规则保存在内存中,一旦客户端重启,熔断规则将全部丢失。上面介绍了Sentinel客户端配置Nacos数据源,熔断规则持久化到Nacos中。客户端启动时,从Nacos数据源中加载熔断规则,并且会监听Nacos数据源中规则的变化,一旦Nacos中的规则改变,Sentinel客户端也会随之改变。从而,重启后,客户端之前的熔断规则不会丢失,实现熔断规则持久化。

​ 但是Nacos中的规则需要我们手动添加,这样很不方便。通常,我们是在Sentinel控制台添加熔断规则,所以,我们接下来需要做的是,Sentinel控制台 将熔断规则推送到Nacos数据源。

控制台改造主要是为规则实现

  • DynamicRuleProvider:从Nacos上读取配置
  • DynamicRulePublisher:将规则推送到Nacos上
下载控制台源码

下载Sentinel控制台:https://github.com/alibaba/Sentinel/releases

修改POM文件

将sentinel-datasource-nacos的 <scope>test</scope> 这一行注释掉

1
2
3
4
5
6

<!-- for Nacos rule publisher sample -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <scope>test</scope>
</dependency>

如下效果

1
2
3
4
5
6

<!-- for Nacos rule publisher sample -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
    <!--  <scope>test</scope>-->
</dependency>
相关类修改

找到 sentinel-dashboard/src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos目录,将整个目录拷贝到 sentinel-dashboard/src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos

修改NacosConfig类

修改NacosConfig类,修改NacosIP地址

FlowControllerV1修改

自动注入provider和publisher

1
2
3
4
5
6
7

@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;

@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

修改rules接口,读取nacos中的数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

@GetMapping("/rules")
   @AuthAction(PrivilegeType.READ_RULE)
   public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app) {

       if (StringUtil.isEmpty(app)) {
           return Result.ofFail(-1, "app can't be null or empty");
       }
       try {
           List<FlowRuleEntity> rules = ruleProvider.getRules(app);
           if (rules != null && !rules.isEmpty()) {
               for (FlowRuleEntity entity : rules) {
                   entity.setApp(app);
                   if (entity.getClusterConfig() != null && entity.getClusterConfig().getFlowId() != null) {
                       entity.setId(entity.getClusterConfig().getFlowId());
                   }
               }
           }
           rules = repository.saveAll(rules);
           return Result.ofSuccess(rules);
       } catch (Throwable throwable) {
           logger.error("Error when querying flow rules", throwable);
           return Result.ofThrowable(-1, throwable);
       }
   }

该类最后的publishRules方法修改如下

1
2
3
4
5
6
7
8
9
10
11

private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
    List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    try {
        rulePublisher.publish(app, rules);
        logger.info("添加限流规则成功.....");
    } catch (Exception e) {
        e.printStackTrace();
        logger.info("添加限流规则失败.....");
    }
    return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
}

测试

访问http://localhost:8080/可以进入到控制台界面,但是界面上没有任何的客户端

请求一次http://localhost:8083/order/createorder/1,等一会儿,刷新一下就可以看到客户端了

添加流控规则

并刷新一下就可以看到我们添加的规则了

在nacos配置中心查看

我们发现配置已经被推送到了nacos

重启客户端进行测试

重启客户端后发现我们的规则是生效的,并且修改规则后重启客户端规则也是生效的

访问 http://localhost:8083/order/createorder/1 进行测试

降级规则推送Nacos

控制台源码修改

是在前面已经完成限流规则推送的控制台代码基础上继续修改的

相关类修改
修改NacosConfigUtil

添加降级规则后缀

1

public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";

添加降级规则推送类

复制限流规则并进行重命名

修改DegradeRuleNacosProvider类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

@Component("degradeRuleNacosProvider")
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<String, List<DegradeRuleEntity>> converter;

    @Override
    public List<DegradeRuleEntity> getRules(String appName) throws Exception {
        String rules = configService.getConfig(appName + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
            NacosConfigUtil.GROUP_ID, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}

修改DegradeRuleNacosPublisher类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

@Component("degradeRuleNacosPublisher")
public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<List<DegradeRuleEntity>, String> converter;

    @Override
    public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }
        configService.publishConfig(app + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
                NacosConfigUtil.GROUP_ID, converter.convert(rules));
    }
}
注入降级规则转换器

规则转换器是负责将降级规则对象转换为json字符串

在 NacosConfig 类中添加注入两个转换器

1
2
3
4
5
6
7
8
9
10

@Bean
public Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {
    return JSON::toJSONString;
}

@Bean
public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
    return s -> JSON.parseArray(s, DegradeRuleEntity.class);

}

修改DegradeController

使用NacosPublisher推送规则,代替之前的直接推送到Sentinel客户端的方式

自动注入provider和publisher

1
2
3
4
5
6
7

@Autowired
@Qualifier("degradeRuleNacosProvider")
private DynamicRuleProvider<List<DegradeRuleEntity>> provider;

@Autowired
@Qualifier("degradeRuleNacosPublisher")
private DynamicRulePublisher<List<DegradeRuleEntity>> publisher;

修改DegradeController的publishRules方法

1
2
3
4
5
6
7
8
9
10
11

private boolean publishRules(String app, String ip, Integer port) {
    List<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
    try {
        publisher.publish(app, rules);
        logger.info("推送限流规则到Nacos数据源成功.....");
    } catch (Exception e) {
        e.printStackTrace();
        logger.info("推送限流规则到Nacos数据源失败.....");
    }
    return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
}

编译运行

到这里控制台代码端的代码修改完成了,编译运行没有报错就可以了

测试

启动Nacos控制台新增降级规则

我们发现sentinel已经将降级规则同步了nacos中,dataId是:order-server-degrade-rules

降级内容如下

Sentinel客户端配置

引入POM依赖(省略)
修改配置文件

默认sentinel控制台推送到nacos的dataId定义为: ${spring.application.name}-degrade-rules

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

server.port=8083
# 配置中心url
spring.application.name=order-server
#注册中心地址
spring.cloud.nacos.server-addr=192.168.64.128:8848
#添加sentinel依赖后 暴露/actuator/sentinel端点
# 开启健康检查
management.endpoints.web.exposure.include=*
management.endpoint.health.show-details=ALWAYS
#打开/关闭掉对Spring MVC端点的保护
spring.cloud.sentinel.filter.enabled=false
#这里的 spring.cloud.sentinel.transport.port 端口配置会在应用对应的机器上启动一个 Http Server,该 Server 会与 Sentinel 控制台做交互。比如 Sentinel 控制台添加了1个限流规则,会把规则数据 push 给这个 Http Server 接收,Http Server 再将规则注册到 Sentinel 中。
spring.cloud.sentinel.transport.port=8731
#指定sentinel控制台的地址
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8080

# 设置Sentinel Nacos数据源配置;其中ds是数据源名,可以自行随意修改
# Nacos数据源地址(需要启动一台Nacos Server)
# nacos 地址
spring.cloud.sentinel.datasource.ds.nacos.server-addr=${spring.cloud.nacos.server-addr}
spring.cloud.sentinel.datasource.ds.nacos.dataId=${spring.application.name}-degrade-rules
spring.cloud.sentinel.datasource.ds.nacos.groupId=SENTINEL_GROUP
# 数据类型
spring.cloud.sentinel.datasource.ds3.nacos.data-type=json
# 规则类型
spring.cloud.sentinel.datasource.ds3.nacos.rule-type=degrade
添加Nacos数据源配置类(省略)
测试

启动客户端以及控制台

访问 http://localhost:8083/actuator/sentinel

可以查看到客户端的启动时从Nacos中加载的所有规则

使用postman测试

访问 http://localhost:8083/order/createorder/1

Leave a Reply

电子邮件地址不会被公开。 必填项已用*标注