Sentinel配置规则持久化至Nacos

文中使用的nacos版本1.4.2、sentinel版本1.8.3

问题

当集成了Sentinel的客户端应用重启之后,在控制台配置的规则全部都没有了,如果需要上生产环境需要将规则配置进行持久化。下面就来实现Sentinel规则配置持久化。

添加Maven依赖

需要持久化至nacos就需要添加相关Maven依赖

<!-- Sentinel Datasource 依赖 -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId>
</dependency>

<!-- Sentinel Datasource Nacos 依赖 -->
<dependency>
    <groupId>com.alibaba.csp</groupId>
    <artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

配置

默认 Nacos 适配的 dataId 和 groupId 约定如下:

  • groupId: SENTINEL_GROUP
  • 规则配置 dataId: {appName}-flow-rules,比如应用名为 appA,则 dataId 为 appA-flow-rules
spring:
	cloud:
		sentinel:
			datasource:
			  # 自定义命名
			  flow-rule:
			    # 支持多种持久化数据源:file、nacos、zk、apollo、redis、consul
			    nacos:
			      # naco服务地址
			      server-addr: localhost:8848
			      # 命名空间,根据环境配置
			      namespace: public
			      # 这里我做了一下细分,不同规则设置不同groupId
			      group-id: SENTINEL_FLOW_GROUP
			      # 仅支持JSON和XML类型
			      data-id: ${spring.application.name}-flow-rules.json
			      # 规则类型:flow、degrade、param-flow、system、authority
			      rule-type: flow
			      # nacos开启了认证需要配置username、password
			      # username: nacos
			      # password: nacos
			      

Nacos配置

在这里插入图片描述

[{
	"clusterMode": false,
	"controlBehavior": 0,
	"count": 5.0,
	"grade": 1,
	"limitApp": "default",
	"resource": "/sentinel/flow",
	"strategy": 0
}]

规则配置详细官方文档:https://sentinelguard.io/zh-cn/docs/basic-api-resource-rule.html

配置完成后,重启项目可以看到规则配置依然存在。修改Nacos中的配置也可以实时同步至Sentinel控制台了。
在这里插入图片描述

Sentinel控制台添加的规则推送至Nacos

从上面看来配置的规则可以持久化了,Nacos配置中心修改的规则可能实时同步至Sentinel控制台。但是在控制台中新增、修改、删除规则是无法同步至Nacos配置中心。在控制台添加了一个规则,如果客户端重启,规则就会丢失。下面就来实现控制台添加规则并推送至Nacos。

根据官方文档所述:Sentinel 控制台提供 DynamicRulePublisher 和 DynamicRuleProvider 接口用于实现应用维度的规则推送和拉取。

添加Maven依赖

<!-- 添加Nacos配置中心依赖 -->
<dependency>
    <groupId>com.alibaba.boot</groupId>
    <artifactId>nacos-config-spring-boot-starter</artifactId>
    <version>0.2.10</version>
</dependency>

添加application.properties配置

groupId根据命名约束自定义命名。

# 配置nacos服务地址与命名空间,可根据环境配置命名空间
nacos.config.server-addr=localhost:8848
nacos.config.namespace=8b1673aa-38da-48c6-bc5a-6df956ed0956

# 配置nacos groupId,可以自定义groupId
# 跟上面一样按照不同规则设置不同groupId
sentinel.nacos.flow.group-id=SENTINEL_FLOW_GROUP
sentinel.nacos.degrade.group-id=SENTINEL_DEGRADE_GROUP
sentinel.nacos.auth.group-id=SENTINEL_AUTH_GROUP
sentinel.nacos.param.group-id=SENTINEL_PARAM_GROUP
sentinel.nacos.system.group-id=SENTINEL_SYSTEM_GROUP

自定义FlowRulePublisher推送,并实现DynamicRulePublisher接口

/**
 * @ClassName FlowRulePublisher
 * @Description 推送流控规则
 * @Author tigerkin
 * @Date 2022/3/9 14:40
 */
@Component
public class FlowRulePublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {

    private static final Logger LOG = LoggerFactory.getLogger(FlowRulePublisher.class);

    @Value("${sentinel.nacos.flow.group-id}")
    private String nacosFlowGroupId;

    @Autowired
    private NacosConfigProperties nacosConfigProperties;

    /**
     * 重要属性:
     * resource	        资源名,资源名是限流规则的作用对象
     * count	        限流阈值
     * grade	        限流阈值类型,QPS 或线程数模式	                                 QPS 模式
     * limitApp	        流控针对的调用来源	                                             default,代表不区分调用来源
     * strategy	        调用关系限流策略:直接、链路、关联	                             根据资源本身(直接)
     * controlBehavior	流控效果(直接拒绝 / 排队等待 / 慢启动模式),不支持按调用关系限流	 直接拒绝
     * @param app app name
     * @param rules list of rules to push
     * @throws Exception
     */
    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        if (StringUtil.isBlank(app)) {
            return;
        }
        if (rules == null) {
            return;
        }

        LOG.info("========> 流控规则推送 -> app: {} rules:{}", app, JSON.toJSONString(rules));

        List<FlowRuleEntity> flowFules = rules.stream().map(data -> {
            FlowRuleEntity entity = new FlowRuleEntity();
            entity.setResource(data.getResource());
            entity.setCount(data.getCount());
            entity.setGrade(data.getGrade());
            entity.setLimitApp(data.getLimitApp());
            entity.setStrategy(data.getStrategy());
            entity.setControlBehavior(data.getControlBehavior());
            return entity;
        }).collect(Collectors.toList());

        /**
         * sentinel推送nacos命名约束
         * 流控规则 dataId: {appName}-flow-rules,比如应用名为 appA,则 dataId 为 appA-flow-rules
         */
        String dataId = String.format("%s-flow-rules.json", app);

        HttpHandler.handler(flowFules, nacosConfigProperties, nacosFlowGroupId, dataId);
    }
}

HttpHandler类

/**
 * @ClassName HttpHandler
 * @Description
 * @Author tigerkin
 * @Date 2022/3/10 11:06
 */
public class HttpHandler {

    private static final Logger LOG = LoggerFactory.getLogger(HttpHandler.class);

    public static void handler(Object rules, NacosConfigProperties nacosConfigProperties, String groupId, String dataId) throws IOException {
        StringJoiner param = new StringJoiner("&");
        param.add(String.format("tenant=%s", nacosConfigProperties.getNamespace())); // Nacos 的命名空间ID字段
        param.add(String.format("dataId=%s", dataId));
        param.add(String.format("group=%s", groupId));
        param.add(String.format("content=%s", URLEncoder.encode(JSON.toJSONString(rules), "UTF-8")));
        param.add(String.format("type=%s", "json"));

        String url = String.format("http://%s/nacos/v1/cs/configs?%s", nacosConfigProperties.getServerAddr(), param.toString());
        HttpPost httpPost = new HttpPost(url);

        CloseableHttpClient httpclient = HttpClients.createDefault();

        CloseableHttpResponse response = httpclient.execute(httpPost);
        int statusCode = response.getStatusLine().getStatusCode();
        if (statusCode == 200) {
            HttpEntity entity = response.getEntity();
            String result = EntityUtils.toString(entity);
            LOG.info("========> 发布成功:{}", result);
        } else {
            LOG.error("========> 发布失败:{}", response.toString());
        }
    }
}

实现在推送接口后,找到Sentinel规则配置的Controller,并添加推送逻辑。我这里改造的是FlowControllerV1。

添加依赖注入属性:
在这里插入图片描述
最后在Controller中找到publisherRules方法,添加推送方法调用就可以了。

Sentinel在规则变更后会给客户端发送一个请求,去同步规则配置。

在这里插入图片描述
下面在控制台添加规则,就会推送至Nacos配置中心了。至此Sentinel配置规则持久化至Nacos就完成了。
在这里插入图片描述
在这里插入图片描述
参考:
Nacos Open API 文档:https://nacos.io/zh-cn/docs/open-api.html
Sentinel github地址:https://github.com/alibaba/Sentinel/releases
Sentinel官方文档:
https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel
https://github.com/alibaba/Sentinel/wiki/Sentinel-控制台(集群流控管理)#规则配置

提供相关业务逻辑处理源码位置,有兴趣的童鞋可以看一看。

客户端处理Sentinel请求的源码位置:

jar: sentinel-transport-common-1.8.3.jar
package: com.alibaba.csp.sentinel.command.handler

在这里插入图片描述
nacos监听处理源码位置:

jar: sentinel-datasource-nacos-1.8.3.jar
package: com.alibaba.csp.sentinel.datasource.nacos

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_42270645/article/details/123399569