sentinel整合nacos配置中心持久化

这篇具有很好参考价值的文章主要介绍了sentinel整合nacos配置中心持久化。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在网上找了很多的资料,发现sentinel整合nacos持久化的博文和视频大多数都只有改造限流部分的教程,并且都需要修改前端,略显麻烦,至于剩下的熔断、热点流控、授权的更是没有相关的改造教程,最后在知乎的看到一篇文章后让我大受启发

sentinel整合nacos配置中心持久化,java后端,项目,sentinel,状态模式
这位前辈讲到sentinel原来是把配置保存到内存的,我们只需要找出这行保存到内存的代码,把它改为发布到nacos就可以了,这样做改动非常的小,而且不用改前端,是个非常聪明的思路。

下面是我改造的过程,完全不需要改前端:

注释掉nacos依赖的test作用域
sentinel整合nacos配置中心持久化,java后端,项目,sentinel,状态模式

把test目录下nacos文件夹复制一份到java目录下
sentinel整合nacos配置中心持久化,java后端,项目,sentinel,状态模式

改造NacosConfig 类

/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import java.util.List;
import java.util.Properties;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.ConfigFactory;
import com.alibaba.nacos.api.config.ConfigService;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
@Configuration
public class NacosConfig {

    // 动态配置nacos地址,用户名,密码
    @Value("${sentinel.nacos.serverAddr}")
    private String serverAddr;
    @Value("${sentinel.nacos.username}")
    private String username;
    @Value("${sentinel.nacos.password}")
    private String password;
    
    /**
     * 加入要改造方法所需实体的编解码器
     * @return
     */
    // 流控
    @Bean
    public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
        return JSON::toJSONString;
    }

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

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

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

    // 授权
    @Bean
    public Converter<List<AuthorityRuleEntity>, String> authorityRuleEntityEncoder() {
        return JSON::toJSONString;
    }

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

    // 热点流控
    @Bean
    public Converter<List<ParamFlowRuleEntity>, String> paramFlowRuleEntityEncoder() {
        return JSON::toJSONString;
    }

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

    @Bean
    public ConfigService nacosConfigService() throws Exception {
        Properties properties = new Properties();
        properties.put("serverAddr", serverAddr);
        properties.put("username", username);
        properties.put("password", password);
        return ConfigFactory.createConfigService(properties);
//        return ConfigFactory.createConfigService("localhost");
    }
}

定义发布到配置中心的配置名后缀

/*
 * Copyright 1999-2018 Alibaba Group Holding Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.alibaba.csp.sentinel.dashboard.rule.nacos;

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
public final class NacosConfigUtil {

    public static final String GROUP_ID = "SENTINEL_GROUP";
    
    // 定义发布到配置中心的配置名后缀
    public static final String FLOW_DATA_ID_POSTFIX = "-flow-rules";
    public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";
    public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules";
    public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
    public static final String CLUSTER_MAP_DATA_ID_POSTFIX = "-cluster-map";

    /**
     * cc for `cluster-client`
     */
    public static final String CLIENT_CONFIG_DATA_ID_POSTFIX = "-cc-config";
    /**
     * cs for `cluster-server`
     */
    public static final String SERVER_TRANSPORT_CONFIG_DATA_ID_POSTFIX = "-cs-transport-config";
    public static final String SERVER_FLOW_CONFIG_DATA_ID_POSTFIX = "-cs-flow-config";
    public static final String SERVER_NAMESPACE_SET_DATA_ID_POSTFIX = "-cs-namespace-set";

    private NacosConfigUtil() {}

}

配置文件中加入需要自定义的配置

#spring settings
server.servlet.encoding.force=true
server.servlet.encoding.charset=UTF-8
server.servlet.encoding.enabled=true

#cookie name setting
server.servlet.session.cookie.name=sentinel_dashboard_cookie

#logging settings
logging.level.org.springframework.web=INFO
logging.file.name=${user.home}/logs/csp/sentinel-dashboard.log
logging.pattern.file= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n
#logging.pattern.console= %d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n

#auth settings
auth.filter.exclude-urls=/,/auth/login,/auth/logout,/registry/machine,/version
auth.filter.exclude-url-suffixes=htm,html,js,css,map,ico,ttf,woff,png
# If auth.enabled=false, Sentinel console disable login
auth.username=sentinel
auth.password=sentinel

# Inject the dashboard version. It's required to enable
# filtering in pom.xml for this resource file.
sentinel.dashboard.version=@project.version@

sentinel.nacos.serverAddr = 127.0.0.1:8848
sentinel.nacos.username = nacos
sentinel.nacos.password = nacos
sentinel.nacos.groupId = SENTINEL_GROUP

# custom dataId postfix
sentinel.custom.FLOW_DATA_ID_POSTFIX =
sentinel.custom.DEGRADE_DATA_ID_POSTFIX =
sentinel.custom.AUTHORITY_DATA_ID_POSTFIX =
sentinel.custom.PARAM_FLOW_DATA_ID_POSTFIX =

FlowRuleNacosProvider 类改造

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<String, List<FlowRuleEntity>> converter;
    // 增加的代码
    @Value("${sentinel.nacos.groupId}")
    private String groupId;
    // 增加的代码
    @Value("${sentinel.custom.FLOW_DATA_ID_POSTFIX}")
    private String dataIdPostfix;

    @Override
    public List<FlowRuleEntity> getRules(String appName) throws Exception {
        // 增加的代码 用于判断是否自定义dataid后缀
        if (dataIdPostfix.isEmpty()){
            dataIdPostfix = NacosConfigUtil.FLOW_DATA_ID_POSTFIX;
        }
        String rules = configService.getConfig(appName + dataIdPostfix,
                groupId, 3000);
        if (StringUtil.isEmpty(rules)) {
            return new ArrayList<>();
        }
        return converter.convert(rules);
    }
}

FlowRuleNacosPublisher 类的改造

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import java.util.List;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * @author Eric Zhao
 * @since 1.4.0
 */
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
    
    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<List<FlowRuleEntity>, String> converter;
    // 增加的代码
    @Value("${sentinel.nacos.groupId}")
    private String groupId;
    // 增加的代码
    @Value("${sentinel.custom.FLOW_DATA_ID_POSTFIX}")
    private String dataIdPostfix;

    @Override
    public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
        // 增加的代码 用于判断是否自定义dataid后缀
        if (dataIdPostfix.isEmpty()){
            dataIdPostfix = NacosConfigUtil.FLOW_DATA_ID_POSTFIX;
        }
        AssertUtil.notEmpty(app, "app name cannot be empty");
        if (rules == null) {
            return;
        }
//        configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
//            NacosConfigUtil.GROUP_ID, converter.convert(rules));
        configService.publishConfig(app + dataIdPostfix,
                groupId, converter.convert(rules));
    }
}

熔断、授权、热点流控Provider和Publisher的改造与流控的类似,改下对应实体类型、后缀、组件名即可

FlowControllerV1 类的改造

package com.alibaba.csp.sentinel.dashboard.controller;

import java.util.Date;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.util.StringUtil;

import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.InMemoryRuleRepositoryAdapter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * Flow rule controller.
 *
 * @author leyou
 * @author Eric Zhao
 */
@RestController
@RequestMapping(value = "/v1/flow")
public class FlowControllerV1 {

    private final Logger logger = LoggerFactory.getLogger(FlowControllerV1.class);

    @Autowired
    private InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;
    @Autowired
    private AppManagement appManagement;

    @Autowired
    private SentinelApiClient sentinelApiClient;

    // 增加的代码,注入用于发布nacos配置的类
    @Autowired
    @Qualifier("flowRuleNacosProvider")
    private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("flowRuleNacosPublisher")
    private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;

    @GetMapping("/rules")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app,
                                                             @RequestParam String ip,
                                                             @RequestParam Integer port) {
        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        if (StringUtil.isEmpty(ip)) {
            return Result.ofFail(-1, "ip can't be null or empty");
        }
        if (port == null) {
            return Result.ofFail(-1, "port can't be null");
        }
        if (!appManagement.isValidMachineOfApp(app, ip)) {
            return Result.ofFail(-1, "given ip does not belong to given app");
        }
        try {
//            List<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);
            // 增加的代码,把查询内存改为查询naocos配置中心
            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);
        }
    }
	...
    private CompletableFuture<Void> publishRules(String app, String ip, Integer port) throws Exception {
        List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        // 增加的代码,把新增的规则发布到指定的nacos配置中心
        rulePublisher.publish(app, rules);
        // 保留保存到内存的逻辑
        return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
    }
}

DegradeController 类改造

package com.alibaba.csp.sentinel.dashboard.controller;

import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.slots.block.degrade.circuitbreaker.CircuitBreakerStrategy;
import com.alibaba.csp.sentinel.util.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.*;

import java.util.Date;
import java.util.List;

/**
 * Controller regarding APIs of degrade rules. Refactored since 1.8.0.
 *
 * @author Carpenter Lee
 * @author Eric Zhao
 */
@RestController
@RequestMapping("/degrade")
public class DegradeController {

    private final Logger logger = LoggerFactory.getLogger(DegradeController.class);

    @Autowired
    private RuleRepository<DegradeRuleEntity, Long> repository;
    @Autowired
    private SentinelApiClient sentinelApiClient;

    // 增加的代码,注入用于发布nacos配置的类
    @Autowired
    @Qualifier("degradeRuleNacosProvider")
    private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("degradeRuleNacosPublisher")
    private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;
    
    @Autowired
    private AppManagement appManagement;

    @GetMapping("/rules.json")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<DegradeRuleEntity>> apiQueryMachineRules(String app, String ip, Integer port) {
        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app can't be null or empty");
        }
        if (StringUtil.isEmpty(ip)) {
            return Result.ofFail(-1, "ip can't be null or empty");
        }
        if (port == null) {
            return Result.ofFail(-1, "port can't be null");
        }
        if (!appManagement.isValidMachineOfApp(app, ip)) {
            return Result.ofFail(-1, "given ip does not belong to given app");
        }
        try {
            // 增加的代码 查询nacos配置中心
            List<DegradeRuleEntity> rules = ruleProvider.getRules(app);
            if (rules != null && !rules.isEmpty()) {
                for (DegradeRuleEntity entity : rules) {
                    entity.setApp(app);
                }
            }
//            List<DegradeRuleEntity> rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);
        } catch (Throwable throwable) {
            logger.error("queryApps error:", throwable);
            return Result.ofThrowable(-1, throwable);
        }
    }
	....
    private boolean publishRules(String app, String ip, Integer port) throws Exception {
        List<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        // 增加的代码 保存到nacos
        rulePublisher.publish(app, rules);
        return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
    }
}

AuthorityRuleController 类的改造

import java.util.Date;
import java.util.List;

import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.StringUtil;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Eric Zhao
 * @since 0.2.1
 */
@RestController
@RequestMapping(value = "/authority")
public class AuthorityRuleController {

    private final Logger logger = LoggerFactory.getLogger(AuthorityRuleController.class);

    @Autowired
    private SentinelApiClient sentinelApiClient;
    @Autowired
    private RuleRepository<AuthorityRuleEntity, Long> repository;
    @Autowired
    private AppManagement appManagement;
    
    // 增加的代码,注入用于发布nacos配置的类
    @Autowired
    @Qualifier("authorityRuleNacosProvider")
    private DynamicRuleProvider<List<AuthorityRuleEntity>> ruleProvider;
    @Autowired
    @Qualifier("authorityRuleNacosPublisher")
    private DynamicRulePublisher<List<AuthorityRuleEntity>> rulePublisher;

    @GetMapping("/rules")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<AuthorityRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
                                                                        @RequestParam String ip,
                                                                        @RequestParam Integer port) {
        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app cannot be null or empty");
        }
        if (StringUtil.isEmpty(ip)) {
            return Result.ofFail(-1, "ip cannot be null or empty");
        }
        if (port == null || port <= 0) {
            return Result.ofFail(-1, "Invalid parameter: port");
        }
        if (!appManagement.isValidMachineOfApp(app, ip)) {
            return Result.ofFail(-1, "given ip does not belong to given app");
        }
        try {
//            List<AuthorityRuleEntity> rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
            // 增加的代码 查询nacos配置中心
            List<AuthorityRuleEntity> rules = ruleProvider.getRules(app);
            if (rules != null && !rules.isEmpty()) {
                for (AuthorityRuleEntity entity : rules) {
                    entity.setApp(app);
                }
            }
            rules = repository.saveAll(rules);
            return Result.ofSuccess(rules);
        } catch (Throwable throwable) {
            logger.error("Error when querying authority rules", throwable);
            return Result.ofFail(-1, throwable.getMessage());
        }
    }
    
	...
	
    private boolean publishRules(String app, String ip, Integer port) throws Exception {
        List<AuthorityRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        // 增加的代码 保存到nacos
        rulePublisher.publish(app, rules);
        return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
    }
}

ParamFlowRuleController 类的改造,Provider查询类返回类型不同,对应的Provider类也要做相应的修改

package com.alibaba.csp.sentinel.dashboard.controller;

import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;

import com.alibaba.csp.sentinel.dashboard.auth.AuthAction;
import com.alibaba.csp.sentinel.dashboard.client.CommandNotFoundException;
import com.alibaba.csp.sentinel.dashboard.client.SentinelApiClient;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.discovery.AppManagement;
import com.alibaba.csp.sentinel.dashboard.discovery.MachineInfo;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService;
import com.alibaba.csp.sentinel.dashboard.auth.AuthService.PrivilegeType;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.ParamFlowRuleNacosProvider;
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.SentinelVersion;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.domain.Result;
import com.alibaba.csp.sentinel.dashboard.repository.rule.RuleRepository;
import com.alibaba.csp.sentinel.dashboard.util.VersionUtils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author Eric Zhao
 * @since 0.2.1
 */
@RestController
@RequestMapping(value = "/paramFlow")
public class ParamFlowRuleController {

    private final Logger logger = LoggerFactory.getLogger(ParamFlowRuleController.class);

    @Autowired
    private SentinelApiClient sentinelApiClient;
    @Autowired
    private AppManagement appManagement;
    @Autowired
    private RuleRepository<ParamFlowRuleEntity, Long> repository;

    // 增加的代码,注入用于发布nacos配置的类
    // 这个查询返回的类型与其他三个方法有些区别
    @Autowired
    @Qualifier("paramFlowRuleNacosProvider")
    private ParamFlowRuleNacosProvider ruleProvider;
    @Autowired
    @Qualifier("paramFlowRuleNacosPublisher")
    private DynamicRulePublisher<List<ParamFlowRuleEntity>> rulePublisher;

    private boolean checkIfSupported(String app, String ip, int port) {
        try {
            return Optional.ofNullable(appManagement.getDetailApp(app))
                .flatMap(e -> e.getMachine(ip, port))
                .flatMap(m -> VersionUtils.parseVersion(m.getVersion())
                    .map(v -> v.greaterOrEqual(version020)))
                .orElse(true);
            // If error occurred or cannot retrieve machine info, return true.
        } catch (Exception ex) {
            return true;
        }
    }

    @GetMapping("/rules")
    @AuthAction(PrivilegeType.READ_RULE)
    public Result<List<ParamFlowRuleEntity>> apiQueryAllRulesForMachine(@RequestParam String app,
                                                                        @RequestParam String ip,
                                                                        @RequestParam Integer port) {
        if (StringUtil.isEmpty(app)) {
            return Result.ofFail(-1, "app cannot be null or empty");
        }
        if (StringUtil.isEmpty(ip)) {
            return Result.ofFail(-1, "ip cannot be null or empty");
        }
        if (port == null || port <= 0) {
            return Result.ofFail(-1, "Invalid parameter: port");
        }
        if (!appManagement.isValidMachineOfApp(app, ip)) {
            return Result.ofFail(-1, "given ip does not belong to given app");
        }
        if (!checkIfSupported(app, ip, port)) {
            return unsupportedVersion();
        }
        try {
            // 增加的代码 查询nacos配置中心 与其他三个方法有些区别
            return ruleProvider.getRules(app)
                    .thenApply(repository::saveAll)
                    .thenApply(Result::ofSuccess)
                    .get();
//            return sentinelApiClient.fetchParamFlowRulesOfMachine(app, ip, port)
//                    .thenApply(repository::saveAll)
//                    .thenApply(Result::ofSuccess)
//                    .get();
        } catch (ExecutionException ex) {
            logger.error("Error when querying parameter flow rules", ex.getCause());
            if (isNotSupported(ex.getCause())) {
                return unsupportedVersion();
            } else {
                return Result.ofThrowable(-1, ex.getCause());
            }
        } catch (Throwable throwable) {
            logger.error("Error when querying parameter flow rules", throwable);
            return Result.ofFail(-1, throwable.getMessage());
        }
    }

    private boolean isNotSupported(Throwable ex) {
        return ex instanceof CommandNotFoundException;
    }
	...
    private CompletableFuture<Void> publishRules(String app, String ip, Integer port) throws Exception {
        List<ParamFlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
        // 增加的代码 保存到nacos
        rulePublisher.publish(app, rules);
        return sentinelApiClient.setParamFlowRuleOfMachine(app, ip, port, rules);
    }
}

具体的ParamFlowRuleNacosProvider 类

package com.alibaba.csp.sentinel.dashboard.rule.nacos;

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.concurrent.CompletableFuture;

/**
 * @ClassName: ParamFlowRuleNacosProvider
 * @Description: TODO
 * @Author: ChiKin Lau @ SUSE
 * @Date: 2023/11/8 10:08
 * @version: 1.0
 **/
@Component("paramFlowRuleNacosProvider")
public class ParamFlowRuleNacosProvider {

    @Autowired
    private ConfigService configService;
    @Autowired
    private Converter<String, List<ParamFlowRuleEntity>> converter;
    // 增加的代码
    @Value("${sentinel.nacos.groupId}")
    private String groupId;
    @Value("${sentinel.custom.PARAM_FLOW_DATA_ID_POSTFIX}")
    private String dataIdPostfix;

    public CompletableFuture<List<ParamFlowRuleEntity>> getRules(String appName) throws Exception {
        // 增加的代码 用于判断是否自定义dataid后缀
        if (dataIdPostfix.isEmpty()){
            dataIdPostfix = NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX;
        }
        String rules = configService.getConfig(appName + dataIdPostfix,
                groupId, 3000);
//        if (StringUtil.isEmpty(rules)) {
//            return new CompletableFuture<>();
//        }
        // 增加的代码 用于适应不同的返回类型
        CompletableFuture<String> future = new CompletableFuture<>();
        future.complete(rules);
        return future.thenApply(json -> JSON.parseArray(json, ParamFlowRuleEntity.class));
    }
}

OK,至此所有的改造完成了,使用maven进行打包即可使用,使用这个jar包在页面端的sentinel配可以保存到nacos进行持久化了,包括了流控、熔断、授权和热点限流。
sentinel整合nacos配置中心持久化,java后端,项目,sentinel,状态模式

下面附上

源码的GitHub地址: https://github.com/chikin-lau/sentinel-nacos
jar包及使用说明压缩包:
链接:https://pan.baidu.com/s/1jvcSCQw-YjeT5-nRocQOUA
提取码:8xry
–来自百度网盘超级会员V3的分享

参考文章:
https://zhuanlan.zhihu.com/p/663149010文章来源地址https://www.toymoban.com/news/detail-757102.html

到了这里,关于sentinel整合nacos配置中心持久化的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Nacos作为服务配置中心、集群和持久化配置

    目录 一、Nacos作为服务配置中心演示 (一)Nacos作为配置中心-基础配置 (二)Nacos作为配置中心-分类配置 二、Nacos集群和持久化配置(重要) (一)官网说明 (二)Nacos持久化配置解释 1、Nacos默认自带的是嵌入式数据库derby 2、derby到mysql切换配置步骤 (三)Linux版Nacos+MyS

    2024年02月09日
    浏览(51)
  • Sentinel nacos spring cloud 持久化配置---分布式/微服务流量控制

    下载地址:https://github.com/alibaba/Sentinel/releases 本次版本:1.8.6 上一篇文章已介绍 我们先说目标,为各位看官节省不匹配的时间 0、使用sentinel流控中心 1、使用nacos做配置中心 5、使用spring-cloud-starter-alibaba-sentinel做持久化配置 https://github.com/OrderDong/microservice-boot 分支:microserv

    2024年02月16日
    浏览(49)
  • Sentinel 规则持久化到 Nacos

    Sentinel的控制台规则管理有三种模式: 原始模式:控制台配置的规则直接推送到Sentinel客户端,也就是我们的应用。然后保存在内存中,服务重启则丢失 pull模式:控制台将配置的规则推送到Sentinel客户端,而客户端会将配置规则保存在本地文件或数据库中。以后会定时去本地

    2024年02月16日
    浏览(47)
  • Sentinel-Dashboard-1.8持久化Nacos

    Sentinel-Dashboard-1.8持久化Nacos 一、客户端改造 1.引入pom.xml文件依赖 2.配置application.yml文件。 客户端改造完成 二、Sentinel-Dashboard源码改造 1.修改pom.xml中nacos的范围中【test】注释。 2.把test目录下com/alibaba/csp/sentinel/dashboard/rule下的nacos文件夹复制到main相同目录下 3.修改application.

    2024年02月04日
    浏览(34)
  • SpringCloudAlibaba微服务实战系列(五)Sentinel1.8.5+Nacos持久化

    前面介绍Sentinel的流控、熔断降级等功能,同时Sentinel应用也在面临着一个问题:我们在Sentinel后台管理界面中配置了一堆流控、降级规则,但是Sentinel一重启,这些规则全部消失了。那么我们就要考虑Sentinel的持久化问题。 Sentinel为我们提供了几种持久化的解决方案: 存储到

    2024年02月10日
    浏览(48)
  • (十五)docker安装sentinel,客户端配置规则本地持久化

    操作系统: Linux  CentOS 7.3 64位 docker版本: 19.03.8 sentinel版本: 1.8.0 1、拉取镜像   2、运行容器   3.访问sentinel http://192.168.121.132:8858/ 账号密码默认都是sentinel ​ sentinel配置的规则默认是存在内存里的,不够稳定,所以我们需要持久化到本地文件中。 1.新建持久化处理类 在我

    2024年02月08日
    浏览(48)
  • 【深入了解Nacos集群和持久化配置】 ——每天一点小知识

                                                                                   💧 深入了解 N a c o s 集群和持久化配置 color{#FF1493}{深入了解Nacos集群和持久化配置} 深入了解 N a cos 集群和持久化配置 💧           🌷 仰望天空,妳

    2024年02月11日
    浏览(44)
  • Sentinel规则持久化

    首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。 示例代码: 1.编写处理类 2.添加配置 在resources下创建配置目录 META-INF/services ,然后添加文件 com.alibaba.csp.sentinel.init.InitFunc 在文件中添加配置类的全路径

    2024年02月13日
    浏览(40)
  • Sentinel 规则持久化

    需要大量修改源码,很麻烦,下面也只是修改了一小部分 阿里有一个收费的sentinel云服务,开源sentinel没有实现最佳版本可能就是为了给收费版让路吧 修改OrderService,让其监听Nacos中的sentinel规则配置。 具体步骤如下: 1.引入依赖 在order-service中引入sentinel监听nacos的依赖:

    2024年02月12日
    浏览(38)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包