sentinel整合nacos配置中心持久化

在網上找了很多的資料,發現sentinel整合nacos持久化的博文和視頻大多數都只有改造限流部分的教程,并且都需要修改前端,略顯麻煩,至于剩下的熔斷、熱點流控、授權的更是沒有相關的改造教程,最后在知乎的看到一篇文章后讓我大受啟發

在這里插入圖片描述
這位前輩講到sentinel原來是把配置保存到內存的,我們只需要找出這行保存到內存的代碼,把它改為發布到nacos就可以了,這樣做改動非常的小,而且不用改前端,是個非常聰明的思路。

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

注釋掉nacos依賴的test作用域
在這里插入圖片描述

把test目錄下nacos文件夾復制一份到java目錄下
在這里插入圖片描述

改造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*/// 流控@Beanpublic Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {return s -> JSON.parseArray(s, FlowRuleEntity.class);}// 熔斷@Beanpublic Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {return s -> JSON.parseArray(s, DegradeRuleEntity.class);}// 授權@Beanpublic Converter<List<AuthorityRuleEntity>, String> authorityRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<AuthorityRuleEntity>> authorityRuleEntityDecoder() {return s -> JSON.parseArray(s, AuthorityRuleEntity.class);}// 熱點流控@Beanpublic Converter<List<ParamFlowRuleEntity>, String> paramFlowRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<ParamFlowRuleEntity>> paramFlowRuleEntityDecoder() {return s -> JSON.parseArray(s, ParamFlowRuleEntity.class);}@Beanpublic 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>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<String, List<FlowRuleEntity>> converter;// 增加的代碼@Value("${sentinel.nacos.groupId}")private String groupId;// 增加的代碼@Value("${sentinel.custom.FLOW_DATA_ID_POSTFIX}")private String dataIdPostfix;@Overridepublic 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>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<List<FlowRuleEntity>, String> converter;// 增加的代碼@Value("${sentinel.nacos.groupId}")private String groupId;// 增加的代碼@Value("${sentinel.custom.FLOW_DATA_ID_POSTFIX}")private String dataIdPostfix;@Overridepublic 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);@Autowiredprivate InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;@Autowiredprivate AppManagement appManagement;@Autowiredprivate 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);@Autowiredprivate RuleRepository<DegradeRuleEntity, Long> repository;@Autowiredprivate SentinelApiClient sentinelApiClient;// 增加的代碼,注入用于發布nacos配置的類@Autowired@Qualifier("degradeRuleNacosProvider")private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;@Autowired@Qualifier("degradeRuleNacosPublisher")private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;@Autowiredprivate 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));// 增加的代碼 保存到nacosrulePublisher.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);@Autowiredprivate SentinelApiClient sentinelApiClient;@Autowiredprivate RuleRepository<AuthorityRuleEntity, Long> repository;@Autowiredprivate 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));// 增加的代碼 保存到nacosrulePublisher.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);@Autowiredprivate SentinelApiClient sentinelApiClient;@Autowiredprivate AppManagement appManagement;@Autowiredprivate 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));// 增加的代碼 保存到nacosrulePublisher.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 {@Autowiredprivate ConfigService configService;@Autowiredprivate 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進行持久化了,包括了流控、熔斷、授權和熱點限流。
在這里插入圖片描述

下面附上

源碼的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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/211948.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/211948.shtml
英文地址,請注明出處:http://en.pswp.cn/news/211948.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

百科詞條可以刪除嗎?如何刪除自己的百度百科?

近日&#xff0c;小馬識途營銷顧問接到不少客戶刪除自己百科詞條的咨詢&#xff0c;有不少人自己并沒有去建立百科詞條&#xff0c;但是網上已經有了&#xff0c;有的信息不正確&#xff0c;甚至有的信息是負能量的&#xff0c;對當事人自己造成一定的困擾&#xff0c;所以尋求…

pytorch學習4-簡易卷積實現

系列文章目錄 pytorch學習1-數據加載以及Tensorboard可視化工具pytorch學習2-Transforms主要方法使用pytorch學習3-torchvisin和Dataloader的使用pytorch學習4-簡易卷積實現pytorch學習5-最大池化層的使用pytorch學習6-非線性變換&#xff08;ReLU和sigmoid&#xff09;pytorc…

【鴻蒙學習網絡】

鴻蒙技術學習相關學習資料 官方文檔&#xff1a;華為官方提供了鴻蒙開發者文檔&#xff0c;包括開發指南、API參考和示例代碼等。您可以訪問華為開發者中心網站&#xff08;https://developer.harmonyos.com/&#xff09;獲取最新的官方文檔和教程。在 線 課 程 &#xff1a; …

PbootCMS 前臺RCE漏洞復現

0x01 產品簡介 PbootCMS是全新內核且永久開源免費的PHP企業網站開發建設管理系統,是一套高效、簡潔、 強悍的可免費商用的PHP CMS源碼,能夠滿足各類企業網站開發建設的需要 0x02 漏洞概述 PbootCMS v<=3.1.6版本中存在模板注入,攻擊者可構造特定的鏈接利用該漏洞,執行…

線程及實現方式

一、線程 線程是一個基本的CPU執行單元&#xff0c;也是程序執行流的最小單位。引入線程之后&#xff0c;不僅是進程之間可以并發&#xff0c;進程內的各線程之間也可以并發&#xff0c;從而進一步提升了系統的并發度&#xff0c;使得一個進程內也可以并發處理各種任務&#x…

c語言的內存函數

memcpy函數 1.調用形式void*memcpy(void*p1,void*p2,int n)&#xff0c;表示從第二個位置復制n個字節到第一個位置&#xff0c;而指針類型為void的原因是他可以復制整型字符型甚至指針結構體類型的數據 2.在遇到\0的時候不會停下來&#xff0c;因為函數執行拷貝靠字節數&…

【Hive】——安裝部署

1 MetaData&#xff08;元數據&#xff09; 2 MetaStore &#xff08;元數據服務&#xff09; 3 MetaStore配置方式 3.1 內嵌模式 3.2 本地模式 3.3 遠程模式 4 安裝前準備 <!-- 整合hive --><property><name>hadoop.proxyuser.root.hosts</name><v…

Java+Swing: 主界面組件布局 整理9

說明&#xff1a;這篇博客是在上一篇的基礎上的&#xff0c;因為上一篇已經將界面的框架搭好了&#xff0c;這篇主要是將里面的組件完善。 分為三個部分&#xff0c;北邊的組件、中間的組件、南邊的組件 // 放置北邊的組件layoutNorth(contentPane);// 放置中間的 Jtablelayou…

Tair(3):Tair入門demo

新建一個maven項目 1 導入依賴 <dependency><groupId>com.taobao.tair</groupId><artifactId>tair-client</artifactId><version>2.3.5</version></dependency><dependency><groupId>com.alibaba</groupId>…

計算日期到天數轉換

根據輸入的日期&#xff0c;計算是這一年的第幾天。 保證年份為4位數且日期合法。 輸入描述&#xff1a;輸入一行&#xff0c;空格分割&#xff0c;分別是年&#xff0c;月&#xff0c;日 輸出描述&#xff1a;輸出是這一年的第幾天 輸入&#xff1a;2012 12 31 輸出&#xff…

Python計時器

制作一個簡單的Python計時器 在本教程中&#xff0c;我們將學習如何使用Python制作一個基礎的計時器。這個計時器將能夠開始計時、暫停、繼續和重置時間。 設計思路 為了建立一個計時器&#xff0c;我們需要定義一個能夠跟蹤時間的變量&#xff0c;并且定期更新顯示的時間。…

Linux權限(用戶角色+文件權限屬性)

Linux權限 文章目錄 Linux權限一.文件權限1.快速掌握修改權限的方法&#xff08;修改文件權限屬性&#xff09;2.對比權限的有無&#xff0c;以及具體的體現3.修改權限的第二套方法&#xff08;修改用戶角色&#xff09;4.文件類型&#xff08;Linux下一切皆文件&#xff09; 二…

049:VUE 引入jquery的方法和配置

第049個 查看專欄目錄: VUE ------ element UI 專欄目標 在vue和element UI聯合技術棧的操控下&#xff0c;本專欄提供行之有效的源代碼示例和信息點介紹&#xff0c;做到靈活運用。 &#xff08;1&#xff09;提供vue2的一些基本操作&#xff1a;安裝、引用&#xff0c;模板使…

springboot基礎(80):redis geospatial的應用

文章目錄 前言redis geospatial如何從地圖上獲取經緯度springboot 的相關方法調用準備redis服務器引用的依賴預設位置的keyGEOADD 添加位置GEORADIUS 獲取指定經緯度附件的停車場&#xff08;deprecated&#xff09;GEORADIUS 獲取指定成員附件的停車場&#xff08;deprecated&…

文心一言API(高級版)使用

文心一言API高級版使用 一、百度文心一言API(高級版)二、使用步驟1、接口2、請求參數3、請求參數示例4、接口 返回示例 三、 如何獲取appKey和uid1、申請appKey:2、獲取appKey和uid 四、重要說明 一、百度文心一言API(高級版) 基于百度文心一言語言大模型的智能文本對話AI機器…

歸并排序--分治法

代碼 #include<iostream> using namespace std;void merge(int arr[], int p, int q, int r, int temp[]) {int i p;int j q 1;int k 0;while (i < q && j < r){if (arr[i] < arr[j]){temp[k] arr[i];}else{temp[k] arr[j];}}while (i < q){t…

智能優化算法應用:基于蟻獅算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼

智能優化算法應用&#xff1a;基于蟻獅算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼 文章目錄 智能優化算法應用&#xff1a;基于蟻獅算法3D無線傳感器網絡(WSN)覆蓋優化 - 附代碼1.無線傳感網絡節點模型2.覆蓋數學模型及分析3.蟻獅算法4.實驗參數設定5.算法結果6.參考文獻7.MA…

ptmalloc:從內存虛擬化說起

前言 本文并不局限于ptmalloc的原理&#xff0c;而是從linux的內存虛擬化和系統調用原理出發&#xff0c;結合各種語言實現&#xff0c;講明內存分配方面的trade off&#xff0c;力圖事無巨細&#xff0c;追根究底。本文內容包括但不限于&#xff1a;NIO原理、0拷貝原理、內存…

Redis 數據的持久化 RDB、AOF、RDB + AOF、No persistence 各自優缺點

文章目錄 一、RDB (Redis Database)1.1 RDB 優勢1.2 RDB 缺點1.3 RDB 如何工作1.4 RDB配置1.5 開啟/關閉&#xff0c;RDB快照策略&#xff0c;save指令1.6 持久化硬盤文件&#xff0c;dbfilename指令1.7 持久化硬盤文件的存儲地址&#xff0c;dir指令 二、AOF (Append Only Fil…

leetcode:643. 子數組最大平均數 I(滑動窗口)

一、題目 鏈接&#xff1a;643. 子數組最大平均數 I - 力扣&#xff08;LeetCode&#xff09; 函數原型&#xff1a; double findMaxAverage(int* nums, int numsSize, int k) 二、思路 滑動窗口&#xff1a; 先計算數組前k個元素總和&#xff0c;作為第一個窗口&#xff0c;默…