sentinel實現控制臺與nacos數據雙向綁定

有兩種方式可以實現:
  • Springboot客戶端相應配置(推薦)
  • 修改sentinel-dashboard的源碼

一、Springboot客戶端做相應配置(推薦

1、添加依賴

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

這里面已經實現了從nacos讀取配置的方法,我們只需實現寫入的方法即可

2、新建NacosWritableDataSource

利用 nacos 的 com.alibaba.nacos.api.config.ConfigService#publishConfig(java.lang.String, java.lang.String, java.lang.String) 方法,既會修改持久化文件,也會同步到對應的微服務

@Slf4j
public class NacosWritableDataSource<T> implements WritableDataSource<T> {private NacosDataSourceProperties nacosDataSourceProperties;private ConfigService configService;private final Converter<T, String> configEncoder;private final Lock lock = new ReentrantLock(true);public NacosWritableDataSource(NacosDataSourceProperties nacosDataSourceProperties,Converter<T, String> configEncoder) {this.nacosDataSourceProperties = nacosDataSourceProperties;this.configEncoder = configEncoder;// 初始化 nacos configServiceinitConfigService();}private void initConfigService() {try {this.configService = NacosFactory.createConfigService(buildProperties(nacosDataSourceProperties));} catch (NacosException e) {log.error("init nacos configService error", e);}}private Properties buildProperties(NacosDataSourceProperties nacosDataSourceProperties) {Properties properties = new Properties();if (StringUtils.hasLength(nacosDataSourceProperties.getServerAddr())) {properties.setProperty(PropertyKeyConst.SERVER_ADDR, nacosDataSourceProperties.getServerAddr());} else {properties.setProperty(PropertyKeyConst.ACCESS_KEY, nacosDataSourceProperties.getAccessKey());properties.setProperty(PropertyKeyConst.SECRET_KEY, nacosDataSourceProperties.getSecretKey());properties.setProperty(PropertyKeyConst.ENDPOINT, nacosDataSourceProperties.getEndpoint());}if (StringUtils.hasLength(nacosDataSourceProperties.getNamespace())) {properties.setProperty(PropertyKeyConst.NAMESPACE, nacosDataSourceProperties.getNamespace());}if (StringUtils.hasLength(nacosDataSourceProperties.getUsername())) {properties.setProperty(PropertyKeyConst.USERNAME, nacosDataSourceProperties.getUsername());}if (StringUtils.hasLength(nacosDataSourceProperties.getPassword())) {properties.setProperty(PropertyKeyConst.PASSWORD, nacosDataSourceProperties.getPassword());}return properties;}@Overridepublic void write(T value) throws Exception {lock.lock();try {// 發布新配置configService.publishConfig(nacosDataSourceProperties.getDataId(), nacosDataSourceProperties.getGroupId(),this.configEncoder.convert(value), ConfigType.JSON.getType());} finally {lock.unlock();}}@Overridepublic void close() throws Exception {}}

3、新建SentinelNacosDataSourceHandler

public class SentinelNacosDataSourceHandler implements SmartInitializingSingleton {private final SentinelProperties sentinelProperties;public SentinelNacosDataSourceHandler(SentinelProperties sentinelProperties) {this.sentinelProperties = sentinelProperties;}// 實現SmartInitializingSingleton 的接口后,當所有非懶加載的單例Bean 都初始化完成以后,Spring 的IOC 容器會調用該接口的 afterSingletonsInstantiated() 方法@Overridepublic void afterSingletonsInstantiated() {sentinelProperties.getDatasource().values().forEach(this::registryWriter);}private void registryWriter(DataSourcePropertiesConfiguration dataSourceProperties) {final NacosDataSourceProperties nacosDataSourceProperties = dataSourceProperties.getNacos();if (nacosDataSourceProperties == null) {return;}final RuleType ruleType = nacosDataSourceProperties.getRuleType();// 通過數據源配置的 ruleType 來注冊數據源switch (ruleType) {case FLOW:WritableDataSource<List<FlowRule>> flowRuleWriter =new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerFlowDataSource(flowRuleWriter);break;case DEGRADE:WritableDataSource<List<DegradeRule>> degradeRuleWriter =new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWriter);break;case PARAM_FLOW:WritableDataSource<List<ParamFlowRule>> paramFlowRuleWriter =new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString);ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWriter);break;case SYSTEM:WritableDataSource<List<SystemRule>> systemRuleWriter =new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerSystemDataSource(systemRuleWriter);break;case AUTHORITY:WritableDataSource<List<AuthorityRule>> authRuleWriter =new NacosWritableDataSource<>(nacosDataSourceProperties, JSON::toJSONString);WritableDataSourceRegistry.registerAuthorityDataSource(authRuleWriter);break;default:break;}}
}

4、添加SentinelNacosDataSourceHandler管理

@Configuration(proxyBeanMethods = false)
@AutoConfigureAfter(SentinelAutoConfiguration.class)
public class SentinelNacosDataSourceConfiguration {@Bean@ConditionalOnMissingBeanpublic SentinelNacosDataSourceHandler sentinelNacosDataSourceHandler(SentinelProperties sentinelProperties) {return new SentinelNacosDataSourceHandler(sentinelProperties);}}

5、添加yml配置

spring:cloud:nacos:sentinel:transport:dashboard: 192.168.252.212:11111eager: trueweb-context-unify: true #是否統一web上下文,默認truedatasource:flow-manage: # 流控管理(這個名稱可以自定義)nacos:namespace: sentinelgroup-id: SENTINEL_GROUPdata-id: ${spring.application.name}-flow-rulesserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}data-type: jsonrule-type: flow # 指定文件配置的是那種規則degrade-manage: # 熔斷管理(這個名稱可以自定義)nacos:namespace: sentinelgroup-id: SENTINEL_GROUPdata-id: ${spring.application.name}-degrade-rulesserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}data-type: jsonrule-type: degradehot-param-manage: # 熱點參數管理(這個名稱可以自定義)nacos:namespace: sentinelgroup-id: SENTINEL_GROUPdata-id: ${spring.application.name}-param-rulesserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}data-type: jsonrule-type: param-flow

現在在Sentinel Dashboard?中新建規則即可自動同步到nacos中

二、sentinel-dashboard源碼修改:

1、在pom.xml中把sentinel-datasource-nacos依賴的scope注釋掉。

        <dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId><!--<scope>test</scope>--></dependency>
二、流控規則

1、在com.alibaba.csp.sentinel.dashboard.rule目錄下創建一個nacos目錄,并將test包下的 FlowRuleNacosProvider、FlowRuleNacosPublisher、NacosConfig 和 NacosConfigUtils都粘貼到nacos目錄

2、新增NacosPropertiesConfiguration配置類

@Configuration
@ConfigurationProperties(prefix = "sentinel.nacos")
public class NacosPropertiesConfiguration {private String serverAddr;private String dataId;private String groupId;private String namespace;private String username;private String password;public String getServerAddr() {return serverAddr;}public void setServerAddr(String serverAddr) {this.serverAddr = serverAddr;}public String getDataId() {return dataId;}public void setDataId(String dataId) {this.dataId = dataId;}public String getGroupId() {return groupId;}public void setGroupId(String groupId) {this.groupId = groupId;}public String getNamespace() {return namespace;}public void setNamespace(String namespace) {this.namespace = namespace;}public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}
}

3、application.properties添加naocs配置

sentinel.nacos.serverAddr=******
sentinel.nacos.username=******
sentinel.nacos.password=******
sentinel.nacos.namespace=sentinel

4、修改 NacosConfig 類以支持自定義配置

//    @Bean
//    public ConfigService nacosConfigService() throws Exception {
//        return ConfigFactory.createConfigService("localhost");
//    }@Beanpublic ConfigService nacosConfigService(NacosPropertiesConfiguration nacosPropertiesConfiguration) throws Exception {Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, nacosPropertiesConfiguration.getServerAddr());properties.put(PropertyKeyConst.NAMESPACE, nacosPropertiesConfiguration.getNamespace());properties.put(PropertyKeyConst.USERNAME, nacosPropertiesConfiguration.getUsername());properties.put(PropertyKeyConst.PASSWORD, nacosPropertiesConfiguration.getPassword());return ConfigFactory.createConfigService(properties);}

5、修改 FlowRuleNacosPublisher 確認配置文件格式為JSON

6、配置 V2 版本 Controller 調用 Nacos 提供的服務層

7、前端頁面源碼修改

文件路徑: src/main/webapp/resources/app/scripts/controllers/identity.js
操作: 將 FlowServiceV1 改為 FlowServiceV2,將 /dashboard/flow/ 改為 /dashboard/v2/flow/。

文件路徑:?src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html

操作: 搜索?dashboard.flowV1?并定位到第 57 行,去掉?V1

文件路徑:?src/main/webapp/resources/app/views/flow_v2.html

操作: 注釋掉回到單機頁面的按鈕。

三、熔斷規則

新增DegradeRuleNacosProvider:

@Component("degradeRuleNacosProvider")
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<String, List<DegradeRuleEntity>> converter;@Overridepublic List<DegradeRuleEntity> getRules(String appName) throws Exception {String rules = configService.getConfig(appName + NacosConfigUtil.DEFRADE_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, 3000);if (StringUtil.isEmpty(rules)) {return new ArrayList<>();}return converter.convert(rules);}
}

新增DegradeRuleNacosPublisher:

@Component("degradeRuleNacosPublisher")
public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<List<DegradeRuleEntity>, String> converter;@Overridepublic 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.DEFRADE_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());}
}

NacosConfigUtil類新增:

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

修改DegradeController:

@RestController
@RequestMapping("/degrade")
public class DegradeController {private final Logger logger = LoggerFactory.getLogger(DegradeController.class);@Autowiredprivate RuleRepository<DegradeRuleEntity, Long> repository;@Autowiredprivate SentinelApiClient sentinelApiClient;@Autowiredprivate AppManagement appManagement;@Autowired@Qualifier("degradeRuleNacosProvider")private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;@Autowired@Qualifier("degradeRuleNacosPublisher")private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;@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 {//List<DegradeRuleEntity> rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);List<DegradeRuleEntity> rules = ruleProvider.getRules(app);rules = repository.saveAll(rules);return Result.ofSuccess(rules);} catch (Throwable throwable) {logger.error("queryApps error:", throwable);return Result.ofThrowable(-1, throwable);}}@PostMapping("/rule")@AuthAction(PrivilegeType.WRITE_RULE)public Result<DegradeRuleEntity> apiAddRule(@RequestBody DegradeRuleEntity entity) {Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);if (checkResult != null) {return checkResult;}Date date = new Date();entity.setGmtCreate(date);entity.setGmtModified(date);try {entity = repository.save(entity);publishRules(entity.getApp());} catch (Throwable t) {logger.error("Failed to add new degrade rule, app={}, ip={}", entity.getApp(), entity.getIp(), t);return Result.ofThrowable(-1, t);}return Result.ofSuccess(entity);}@PutMapping("/rule/{id}")@AuthAction(PrivilegeType.WRITE_RULE)public Result<DegradeRuleEntity> apiUpdateRule(@PathVariable("id") Long id,@RequestBody DegradeRuleEntity entity) {if (id == null || id <= 0) {return Result.ofFail(-1, "id can't be null or negative");}DegradeRuleEntity oldEntity = repository.findById(id);if (oldEntity == null) {return Result.ofFail(-1, "Degrade rule does not exist, id=" + id);}entity.setApp(oldEntity.getApp());entity.setIp(oldEntity.getIp());entity.setPort(oldEntity.getPort());entity.setId(oldEntity.getId());Result<DegradeRuleEntity> checkResult = checkEntityInternal(entity);if (checkResult != null) {return checkResult;}entity.setGmtCreate(oldEntity.getGmtCreate());entity.setGmtModified(new Date());try {entity = repository.save(entity);publishRules(entity.getApp());} catch (Throwable t) {logger.error("Failed to save degrade rule, id={}, rule={}", id, entity, t);return Result.ofThrowable(-1, t);}return Result.ofSuccess(entity);}@DeleteMapping("/rule/{id}")@AuthAction(PrivilegeType.DELETE_RULE)public Result<Long> delete(@PathVariable("id") Long id) {if (id == null) {return Result.ofFail(-1, "id can't be null");}DegradeRuleEntity oldEntity = repository.findById(id);if (oldEntity == null) {return Result.ofSuccess(null);}try {repository.delete(id);publishRules(oldEntity.getApp());} catch (Throwable throwable) {logger.error("Failed to delete degrade rule, id={}", id, throwable);return Result.ofThrowable(-1, throwable);}return Result.ofSuccess(id);}//    private boolean publishRules(String app, String ip, Integer port) {
//        List<DegradeRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
//        return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
//    }private void publishRules(/*@NonNull*/ String app) throws Exception {List<DegradeRuleEntity> rules = repository.findAllByApp(app);rulePublisher.publish(app, rules);}private <R> Result<R> checkEntityInternal(DegradeRuleEntity entity) {if (StringUtil.isBlank(entity.getApp())) {return Result.ofFail(-1, "app can't be blank");}if (StringUtil.isBlank(entity.getIp())) {return Result.ofFail(-1, "ip can't be null or empty");}if (!appManagement.isValidMachineOfApp(entity.getApp(), entity.getIp())) {return Result.ofFail(-1, "given ip does not belong to given app");}if (entity.getPort() == null || entity.getPort() <= 0) {return Result.ofFail(-1, "invalid port: " + entity.getPort());}if (StringUtil.isBlank(entity.getLimitApp())) {return Result.ofFail(-1, "limitApp can't be null or empty");}if (StringUtil.isBlank(entity.getResource())) {return Result.ofFail(-1, "resource can't be null or empty");}Double threshold = entity.getCount();if (threshold == null || threshold < 0) {return Result.ofFail(-1, "invalid threshold: " + threshold);}Integer recoveryTimeoutSec = entity.getTimeWindow();if (recoveryTimeoutSec == null || recoveryTimeoutSec <= 0) {return Result.ofFail(-1, "recoveryTimeout should be positive");}Integer strategy = entity.getGrade();if (strategy == null) {return Result.ofFail(-1, "circuit breaker strategy cannot be null");}if (strategy < CircuitBreakerStrategy.SLOW_REQUEST_RATIO.getType()|| strategy > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {return Result.ofFail(-1, "Invalid circuit breaker strategy: " + strategy);}if (entity.getMinRequestAmount() == null || entity.getMinRequestAmount() <= 0) {return Result.ofFail(-1, "Invalid minRequestAmount");}if (entity.getStatIntervalMs() == null || entity.getStatIntervalMs() <= 0) {return Result.ofFail(-1, "Invalid statInterval");}if (strategy == RuleConstant.DEGRADE_GRADE_RT) {Double slowRatio = entity.getSlowRatioThreshold();if (slowRatio == null) {return Result.ofFail(-1, "SlowRatioThreshold is required for slow request ratio strategy");} else if (slowRatio < 0 || slowRatio > 1) {return Result.ofFail(-1, "SlowRatioThreshold should be in range: [0.0, 1.0]");}} else if (strategy == RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO) {if (threshold > 1) {return Result.ofFail(-1, "Ratio threshold should be in range: [0.0, 1.0]");}}return null;}
}

NacosConfig類新增:

    @Beanpublic Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {return s -> JSON.parseArray(s, DegradeRuleEntity.class);}
四、熱點參數

新增ParamRuleNacosProvider

@Component("paramRuleNacosProvider")
public class ParamRuleNacosProvider implements DynamicRuleProvider<List<ParamFlowRuleEntity>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<String, List<ParamFlowRuleEntity>> converter;@Overridepublic List<ParamFlowRuleEntity> getRules(String appName) throws Exception {String rules = configService.getConfig(appName + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, 3000);if (StringUtil.isEmpty(rules)) {return new ArrayList<>();}return converter.convert(rules);}
}

新增ParamRuleNacosPublisher

@Component("paramRuleNacosPublisher")
public class ParamRuleNacosPublisher implements DynamicRulePublisher<List<ParamFlowRuleEntity>> {@Autowiredprivate ConfigService configService;@Autowiredprivate Converter<List<ParamFlowRuleEntity>, String> converter;@Overridepublic void publish(String app, List<ParamFlowRuleEntity> rules) throws Exception {AssertUtil.notEmpty(app, "app name cannot be empty");if (rules == null) {return;}configService.publishConfig(app + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());}
}

NacosConfigUtil類新增:

public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules";

修改ParamFlowRuleController

@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;@Autowired@Qualifier("paramRuleNacosProvider")private DynamicRuleProvider<List<ParamFlowRuleEntity>> ruleProvider;@Autowired@Qualifier("paramRuleNacosPublisher")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 {
//            return sentinelApiClient.fetchParamFlowRulesOfMachine(app, ip, port)
//                .thenApply(repository::saveAll)
//                .thenApply(Result::ofSuccess)
//                .get();List<ParamFlowRuleEntity> rules = ruleProvider.getRules(app);rules = repository.saveAll(rules);return Result.ofSuccess(rules);} 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;}@PostMapping("/rule")@AuthAction(AuthService.PrivilegeType.WRITE_RULE)public Result<ParamFlowRuleEntity> apiAddParamFlowRule(@RequestBody ParamFlowRuleEntity entity) {Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);if (checkResult != null) {return checkResult;}if (!checkIfSupported(entity.getApp(), entity.getIp(), entity.getPort())) {return unsupportedVersion();}entity.setId(null);entity.getRule().setResource(entity.getResource().trim());Date date = new Date();entity.setGmtCreate(date);entity.setGmtModified(date);try {entity = repository.save(entity);publishRules(entity.getApp());return Result.ofSuccess(entity);} catch (ExecutionException ex) {logger.error("Error when adding new 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 adding new parameter flow rules", throwable);return Result.ofFail(-1, throwable.getMessage());}}private <R> Result<R> checkEntityInternal(ParamFlowRuleEntity entity) {if (entity == null) {return Result.ofFail(-1, "bad rule body");}if (StringUtil.isBlank(entity.getApp())) {return Result.ofFail(-1, "app can't be null or empty");}if (StringUtil.isBlank(entity.getIp())) {return Result.ofFail(-1, "ip can't be null or empty");}if (entity.getPort() == null || entity.getPort() <= 0) {return Result.ofFail(-1, "port can't be null");}if (entity.getRule() == null) {return Result.ofFail(-1, "rule can't be null");}if (StringUtil.isBlank(entity.getResource())) {return Result.ofFail(-1, "resource name cannot be null or empty");}if (entity.getCount() < 0) {return Result.ofFail(-1, "count should be valid");}if (entity.getGrade() != RuleConstant.FLOW_GRADE_QPS) {return Result.ofFail(-1, "Unknown mode (blockGrade) for parameter flow control");}if (entity.getParamIdx() == null || entity.getParamIdx() < 0) {return Result.ofFail(-1, "paramIdx should be valid");}if (entity.getDurationInSec() <= 0) {return Result.ofFail(-1, "durationInSec should be valid");}if (entity.getControlBehavior() < 0) {return Result.ofFail(-1, "controlBehavior should be valid");}return null;}@PutMapping("/rule/{id}")@AuthAction(AuthService.PrivilegeType.WRITE_RULE)public Result<ParamFlowRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,@RequestBody ParamFlowRuleEntity entity) {if (id == null || id <= 0) {return Result.ofFail(-1, "Invalid id");}ParamFlowRuleEntity oldEntity = repository.findById(id);if (oldEntity == null) {return Result.ofFail(-1, "id " + id + " does not exist");}Result<ParamFlowRuleEntity> checkResult = checkEntityInternal(entity);if (checkResult != null) {return checkResult;}if (!checkIfSupported(entity.getApp(), entity.getIp(), entity.getPort())) {return unsupportedVersion();}entity.setId(id);Date date = new Date();entity.setGmtCreate(oldEntity.getGmtCreate());entity.setGmtModified(date);try {entity = repository.save(entity);publishRules(entity.getApp());return Result.ofSuccess(entity);} catch (ExecutionException ex) {logger.error("Error when updating parameter flow rules, id=" + id, ex.getCause());if (isNotSupported(ex.getCause())) {return unsupportedVersion();} else {return Result.ofThrowable(-1, ex.getCause());}} catch (Throwable throwable) {logger.error("Error when updating parameter flow rules, id=" + id, throwable);return Result.ofFail(-1, throwable.getMessage());}}@DeleteMapping("/rule/{id}")@AuthAction(PrivilegeType.DELETE_RULE)public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {if (id == null) {return Result.ofFail(-1, "id cannot be null");}ParamFlowRuleEntity oldEntity = repository.findById(id);if (oldEntity == null) {return Result.ofSuccess(null);}try {repository.delete(id);publishRules(oldEntity.getApp());return Result.ofSuccess(id);} catch (ExecutionException ex) {logger.error("Error when deleting 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 deleting parameter flow rules", throwable);return Result.ofFail(-1, throwable.getMessage());}}//    private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {
//        List<ParamFlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
//        return sentinelApiClient.setParamFlowRuleOfMachine(app, ip, port, rules);
//    }private void publishRules(/*@NonNull*/ String app) throws Exception {List<ParamFlowRuleEntity> rules = repository.findAllByApp(app);rulePublisher.publish(app, rules);}private <R> Result<R> unsupportedVersion() {return Result.ofFail(4041,"Sentinel client not supported for parameter flow control (unsupported version or dependency absent)");}private final SentinelVersion version020 = new SentinelVersion().setMinorVersion(2);
}

NacosConfig類新增:

    @Beanpublic Converter<List<ParamFlowRuleEntity>, String> paramRuleEntityEncoder() {return JSON::toJSONString;}@Beanpublic Converter<String, List<ParamFlowRuleEntity>> paramRuleEntityDecoder() {return s -> JSON.parseArray(s, ParamFlowRuleEntity.class);}
五、客戶端配置

pom添加依賴

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

yml文件添加配置

spring:cloud:sentinel:transport:dashboard: 127.0.0.1:8080eager: trueweb-context-unify: true #是否統一web上下文,默認truedatasource:flow-manage: # 流控管理(這個名稱可以自定義)nacos:namespace: sentinelgroup-id: SENTINEL_GROUPdata-id: ${spring.application.name}-flow-rulesserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}data-type: jsonrule-type: flow # 指定文件配置的是那種規則degrade-manage: # 熔斷管理(這個名稱可以自定義)nacos:namespace: sentinelgroup-id: SENTINEL_GROUPdata-id: ${spring.application.name}-degrade-rulesserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}data-type: jsonrule-type: degradehot-param-manage: # 熱點參數管理(這個名稱可以自定義)nacos:namespace: sentinelgroup-id: SENTINEL_GROUPdata-id: ${spring.application.name}-param-rulesserver-addr: ${spring.cloud.nacos.server-addr}username: ${spring.cloud.nacos.username}password: ${spring.cloud.nacos.password}data-type: jsonrule-type: param-flow

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

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

相關文章

Kubernetes (k8s)

Kubernetes (k8s) 以下是一份 ?Kubernetes (k8s) 基礎使用教程&#xff0c;涵蓋從環境搭建到核心操作的完整流程&#xff0c;附詳細命令和示例&#xff1a; &#x1f680; ?一、環境準備&#xff08;3種方式&#xff09;?? ?1. 本地開發環境&#xff08;推薦&#xff09;?…

三打ANSYS HFSS

2. 激勵方式&#xff08;端口&#xff09;詳細對比分析在HFSS中&#xff0c;“激勵方式”和“端口”這兩個詞經常混用&#xff0c;但嚴格來說&#xff0c;“端口”是實現“激勵”的一種最主要的方式。端口類型工作原理適用情況優點缺點波端口 (Wave Port)默認首選。計算端口的固…

3.python——數據類型轉換

python的數據類型轉換分為兩種&#xff1a; 隱式轉換&#xff1a;自動完成 顯式轉換&#xff1a;用類型函數轉換 隱式轉換 # 自動轉為浮點數 num_int 123 num_flo 1.23num_new num_int num_flo顯式轉換 整型 x int(1) # x 輸出結果為 1 y int(2.8) # y 輸出結果為 2 z …

迅為RK3568開發板OpenHarmonyv3.2-Beta4版本測試-命令終端

將串口連接到開發板的調試串口&#xff0c;進入 OpenHarmony 系統后&#xff0c;會自動進入 OpenHarmony終端&#xff0c;如下圖所示&#xff1a;

【面試題】介紹一下BERT和GPT的訓練方式區別?

BERT(雙向編碼器): 預訓練任務: 掩碼語言模型(MLM):隨機掩蓋15%的token,其中: 80%替換為[MASK] 10%替換為隨機token 10%保持原樣 下一句預測(NSP):判斷兩個句子是否連續(后續版本已移除) 訓練特點: 使用雙向Transformer編碼器 同時利用左右上下文信息 適合理解類任…

邪修實戰系列(1)

1、第一階段邪修實戰總覽&#xff08;9.1-9.30&#xff09; 把第一階段&#xff08;基礎夯實期&#xff09;的學習計劃拆解成極具操作性的每日行動方案。這個計劃充分利用我“在職學習”的特殊優勢&#xff0c;強調“用輸出倒逼輸入”&#xff0c;確保每一分鐘的學習都直接服務…

XR數字融合工作站打造智能制造專業學習新范式

智能制造是工業4.0的核心發展方向&#xff0c;涵蓋數字化設計、智能生產、工業機器人、數字孿生、物聯網等關鍵技術。然而&#xff0c;傳統教學模式在設備成本高、實訓風險大、抽象概念難理解等方面存在諸多挑戰。XR數字融合工作站,利用VR/AR/MR等技術&#xff0c;通過虛擬仿真…

基于FPGA實現數字QAM調制系統

基于FPGA實現數字QAM調制系統題目要求一、代碼設計1.頂層2.分頻3.m序列4.串轉并5.映射6.正弦波余弦波生成ROM和7.ask二、仿真波形總結題目要求 FPGA實現數字QAM調制系統要求根據正交振幅調制原理&#xff0c;利用正弦載波信號發生器&#xff0c;實現調制信號。調制原理會利用到…

DAY 22 復習日

浙大疏錦行復習日 仔細回顧一下之前21天的內容&#xff0c;沒跟上進度的同學補一下進度。 作業&#xff1a; 自行學習參考如何使用kaggle平臺&#xff0c;寫下使用注意點&#xff0c;并對下述比賽提交代碼 導入需要的庫 import pandas as pd # 用于數據處理和分析&#xff0c;…

biocmanager安裝 庫 老是提示網絡連接錯誤 才嘗試各種辦法

您好&#xff0c;遇到 BioManager &#xff08;通常是 BiocManager&#xff09;安裝R包時提示網絡連接錯誤確實非常令人頭疼。這通常與R/RStudio的配置、網絡環境&#xff08;尤其是國內用戶&#xff09;或SSL證書問題有關。 請不要著急&#xff0c;我們可以按照從易到難的順序…

【開題答辯全過程】以 智能商品數據分析系統為例,包含答辯的問題和答案

個人簡介一名14年經驗的資深畢設內行人&#xff0c;語言擅長Java、php、微信小程序、Python、Golang、安卓Android等開發項目包括大數據、深度學習、網站、小程序、安卓、算法。平常會做一些項目定制化開發、代碼講解、答辯教學、文檔編寫、也懂一些降重方面的技巧。感謝大家的…

解構復雜財務逆向業務:如何優雅地生成與管理負數單?

文章目錄一 核心復雜性二 關鍵設計模式&#xff1a;三 棘手場景與解決方案&#xff1a;1.分批合并處理&#xff1a;負數單需能智能拆分&#xff0c;精準沖銷多批次的正向單據。2.優先級問題&#xff1a;3.超額處理&#xff1a;系統應堅決攔截而非處理&#xff0c;防止資金損失和…

Android集成OpenCV4實例

Android集成OpenCV4分以下幾步驟&#xff1a; 使用Android Studio Giraffe | 2022.3.1創建一個Empty Views Activity空項目&#xff0c;包名為&#xff1a;com.example.andopencvdemo00 &#xff0c; 創建成功后&#xff0c;進行以下相關設置&#xff1a; 第一步&#xff1a;在…

npy可視化方法

npviewer 是一個應用程序&#xff0c;它允許您以熱圖的形式可視化 numpy 的 npy 文件中的數據。該應用程序根據不同的模式自動選擇適當的維度進行顯示。 根據不同的模式自動選擇適當的維度進行顯示支持不同格式的 numpy 數據的可視化&#xff0c;如 RGB 和灰度用戶友好的界面使…

【Cesium】介紹及基礎使用

文章目錄一、Cesium 介紹二、 使用1、引入 cesium2、Viewer 配置選項1. 基礎控件配置2. 場景與渲染配置3. 地形配置4. 天空與大氣效果3、坐標系系統3.1 地理坐標系3.2 笛卡爾空間直角坐標系3.3 屏幕坐標系4、Entity 實體4.1 簡介4.2 Entity 常見圖形類型Point 點Polyline 線Pol…

基于SpringBoot的運動服裝銷售系統【2026最新】

作者&#xff1a;計算機學姐 開發技術&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源碼”。 專欄推薦&#xff1a;前后端分離項目源碼、SpringBoot項目源碼、Vue項目源碼、SSM項目源碼、微信小程序源碼 精品專欄&#xff1a;…

【嵌入式DIY實例-ESP32篇】-傾斜彈跳球游戲

傾斜彈跳球游戲 文章目錄 傾斜彈跳球游戲 1、MPU6050介紹 2、硬件準備與接線 3、代碼實現 在這個交互式 ESP32 Arduino 項目中,我們模擬了一個綠色球體在全彩 ST7789 170320 LCD 屏幕上彈跳,完全由 MPU6050 陀螺儀的運動控制。當你傾斜傳感器時,球體會呈現出逼真的物理運動,…

從spring MVC角度理解HTTP協議及Request-Response模式

什么是HTTP協議&#xff1f;HTTP協議&#xff08;HyperText Transfer Protocol&#xff0c;超文本傳輸協議&#xff09;是一種通信規則&#xff0c;它定義了客戶端&#xff08;如瀏覽器、手機APP&#xff09; 和服務器 之間如何交換信息&#xff0c;是用于在萬維網&#xff08;…

江協科技STM32學習筆記補充之003 :STM32復位電路的詳細分析

電路作用與每個器件R1&#xff08;10 kΩ&#xff0c;上拉到 3V3&#xff09;讓 NRST 在無外力時保持高電平&#xff1d;不復位&#xff1b;同時與電容形成 RC&#xff0c;決定上電復位延時。阻值不能太小&#xff08;否則調試器或芯片復位驅動下拉電流太大&#xff09;&#x…

Spring Boot HTTP狀態碼詳解

Spring Boot HTTP狀態碼完全指南&#xff1a;從入門到精通 前言 在RESTful API開發中&#xff0c;HTTP狀態碼是與客戶端通信的重要橋梁。Spring Boot通過HttpStatus枚舉提供了完整的HTTP狀態碼支持。本文將深入解析這些狀態碼的含義、使用場景以及在Spring Boot中的最佳實踐。 …