目录
1. 接着上一篇
简单创建一个SpringCloud2021.0.3项目(四)
讲到了Sentinel从Nacos拿配置
2. 思路
- 搜了很多教程,有不用改源码的也有要修改源码。自测不用修改源码方式还是不行,修改源码方式,可能版本不一样导致修改失效。
- 找到官方的解答,Sentinel 控制台(集群流控管理)
- 只要实现推送规则就行
- 在本地内存修改成功后,做我们自定义推送
- 请求进入那个接口,页面F12修改、添加、删除后看看url是什么
- 这里只测试修改限流和熔断降级,热点、授权、系统的没有做
3. 下载Sentinel源码
1.8.3版本页面:https://github.com/alibaba/Sentinel/releases/1.8.3
下载链接:https://github.com/alibaba/Sentinel/archive/refs/tags/1.8.3.zip
4. 看Gateway里面读取的配置信息
Nacos上面的配置
5. 修改Sentinel控制台源码
-
修改sentinel-dashboard模块的依赖,sentinel-datasource-nacos
-
添加配置参数,sentinel-dashboard模块的/Sentinel-1.8.3/sentinel-dashboard/src/main/resources/application.properties
端口看自己情况用默认8080还是自定义
-
添加包com.alibaba.csp.sentinel.dashboard.rule.nacos
在test下面官方给了一些例子,可以拷贝到main里面,也可以用我下面的代码,都会放上来
-
添加配置类NacosPropertiesConfiguration,读取第2步设置的参数
点击查看代码
package com.alibaba.csp.sentinel.dashboard.rule.nacos; import org.springframework.boot.context.properties.ConfigurationProperties; @ConfigurationProperties(prefix = "sentinel.nacos") public class NacosPropertiesConfiguration { private String serverAddr; private String degradeRuleDataId; private String flowRuleDataId; private String groupId = "SENTINEL_GROUP"; private String namespace; private String username; private String password; public String getServerAddr() { return serverAddr; } public void setServerAddr(String serverAddr) { this.serverAddr = serverAddr; } public String getDegradeRuleDataId() { return degradeRuleDataId; } public void setDegradeRuleDataId(String degradeRuleDataId) { this.degradeRuleDataId = degradeRuleDataId; } public String getFlowRuleDataId() { return flowRuleDataId; } public void setFlowRuleDataId(String flowRuleDataId) { this.flowRuleDataId = flowRuleDataId; } 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; } }
- 修改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 com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity; import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity; import com.alibaba.csp.sentinel.datasource.Converter; import com.alibaba.fastjson.JSON; import com.alibaba.nacos.api.PropertyKeyConst; import com.alibaba.nacos.api.config.ConfigFactory; import com.alibaba.nacos.api.config.ConfigService; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import java.util.List; import java.util.Properties; /** * @author Eric Zhao * @since 1.4.0 */ @EnableConfigurationProperties(NacosPropertiesConfiguration.class) @Configuration public class NacosConfig { @Bean public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() { return JSON::toJSONString; } @Bean public Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() { return JSON::toJSONString; } @Bean public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() { return s -> JSON.parseArray(s, FlowRuleEntity.class); } // 以前的 // @Bean // public ConfigService nacosConfigService() throws Exception { // return ConfigFactory.createConfigService("localhost"); // } // 改造后的 @Bean public 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); } }
- 修改FlowRuleNacosPublisher
点击查看代码
/* * 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 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.stereotype.Component; import java.util.List; /** * @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; @Autowired private NacosPropertiesConfiguration nacosPropertiesConfiguration; @Override public void publish(String app, List<FlowRuleEntity> rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } configService.publishConfig(nacosPropertiesConfiguration.getFlowRuleDataId(), nacosPropertiesConfiguration.getGroupId(), converter.convert(rules)); } }
- 添加DegradeRuleNacosPublisher,把FlowRuleNacosPublisher复制修改下类名
点击查看代码
/* * 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 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.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.stereotype.Component; import java.util.List; /** * @author Eric Zhao * @since 1.4.0 */ @Component("degradeRuleNacosPublisher") public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> { @Autowired private ConfigService configService; @Autowired private Converter<List<DegradeRuleEntity>, String> converter; @Autowired private NacosPropertiesConfiguration nacosPropertiesConfiguration; @Override public void publish(String app, List<DegradeRuleEntity> rules) throws Exception { AssertUtil.notEmpty(app, "app name cannot be empty"); if (rules == null) { return; } configService.publishConfig(nacosPropertiesConfiguration.getDegradeRuleDataId(), nacosPropertiesConfiguration.getGroupId(), converter.convert(rules)); } }
- 修改熔断规则推送到Nacos,我这里熔断规则都请求这个类DegradeController,自己的看看是否也是
修改后的com.alibaba.csp.sentinel.dashboard.controller.DegradeController类
/* * 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.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.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.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; @Autowired @Qualifier("degradeRuleNacosPublisher") private DynamicRulePublisher<List<DegradeRuleEntity>> degradeRulePublisher; @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"); } try { 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); } } @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); } catch (Throwable t) { logger.error("Failed to add new degrade rule, app={}, ip={}", entity.getApp(), entity.getIp(), t); return Result.ofThrowable(-1, t); } if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { logger.warn("Publish degrade rules failed, app={}", entity.getApp()); } 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); } catch (Throwable t) { logger.error("Failed to save degrade rule, id={}, rule={}", id, entity, t); return Result.ofThrowable(-1, t); } if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) { logger.warn("Publish degrade rules failed, app={}", entity.getApp()); } 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); } catch (Throwable throwable) { logger.error("Failed to delete degrade rule, id={}", id, throwable); return Result.ofThrowable(-1, throwable); } if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) { logger.warn("Publish degrade rules failed, app={}", oldEntity.getApp()); } 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); // 修改后 boolean b = sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules); if (b) { try { degradeRulePublisher.publish(app, rules); } catch (Exception e) { logger.error("推送熔断策略到Nacos失败, app={}, rule={}", app, rules, e); } } return b; } 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 (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; } }
- 修改限流规则推送到Nacos,我这里熔断规则都请求这个类FlowControllerV1,自己的看看是否也是
修改后的com.alibaba.csp.sentinel.dashboard.controller.FlowControllerV1类
/* * 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.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.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 SentinelApiClient sentinelApiClient; @Autowired @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher<List<FlowRuleEntity>> flowRulePublisher; @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"); } try { List<FlowRuleEntity> rules = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port); 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 <R> Result<R> checkEntityInternal(FlowRuleEntity entity) { 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) { return Result.ofFail(-1, "port can't be null"); } 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"); } if (entity.getGrade() == null) { return Result.ofFail(-1, "grade can't be null"); } if (entity.getGrade() != 0 && entity.getGrade() != 1) { return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got"); } if (entity.getCount() == null || entity.getCount() < 0) { return Result.ofFail(-1, "count should be at lease zero"); } if (entity.getStrategy() == null) { return Result.ofFail(-1, "strategy can't be null"); } if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) { return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0"); } if (entity.getControlBehavior() == null) { return Result.ofFail(-1, "controlBehavior can't be null"); } int controlBehavior = entity.getControlBehavior(); if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) { return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1"); } if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) { return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2"); } if (entity.isClusterMode() && entity.getClusterConfig() == null) { return Result.ofFail(-1, "cluster config should be valid"); } return null; } @PostMapping("/rule") @AuthAction(PrivilegeType.WRITE_RULE) public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) { Result<FlowRuleEntity> checkResult = checkEntityInternal(entity); if (checkResult != null) { return checkResult; } entity.setId(null); Date date = new Date(); entity.setGmtCreate(date); entity.setGmtModified(date); entity.setLimitApp(entity.getLimitApp().trim()); entity.setResource(entity.getResource().trim()); try { entity = repository.save(entity); publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS); return Result.ofSuccess(entity); } catch (Throwable t) { Throwable e = t instanceof ExecutionException ? t.getCause() : t; logger.error("Failed to add new flow rule, app={}, ip={}", entity.getApp(), entity.getIp(), e); return Result.ofFail(-1, e.getMessage()); } } @PutMapping("/save.json") @AuthAction(PrivilegeType.WRITE_RULE) public Result<FlowRuleEntity> apiUpdateFlowRule(Long id, String app, String limitApp, String resource, Integer grade, Double count, Integer strategy, String refResource, Integer controlBehavior, Integer warmUpPeriodSec, Integer maxQueueingTimeMs) { if (id == null) { return Result.ofFail(-1, "id can't be null"); } FlowRuleEntity entity = repository.findById(id); if (entity == null) { return Result.ofFail(-1, "id " + id + " dose not exist"); } if (StringUtil.isNotBlank(app)) { entity.setApp(app.trim()); } if (StringUtil.isNotBlank(limitApp)) { entity.setLimitApp(limitApp.trim()); } if (StringUtil.isNotBlank(resource)) { entity.setResource(resource.trim()); } if (grade != null) { if (grade != 0 && grade != 1) { return Result.ofFail(-1, "grade must be 0 or 1, but " + grade + " got"); } entity.setGrade(grade); } if (count != null) { entity.setCount(count); } if (strategy != null) { if (strategy != 0 && strategy != 1 && strategy != 2) { return Result.ofFail(-1, "strategy must be in [0, 1, 2], but " + strategy + " got"); } entity.setStrategy(strategy); if (strategy != 0) { if (StringUtil.isBlank(refResource)) { return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0"); } entity.setRefResource(refResource.trim()); } } if (controlBehavior != null) { if (controlBehavior != 0 && controlBehavior != 1 && controlBehavior != 2) { return Result.ofFail(-1, "controlBehavior must be in [0, 1, 2], but " + controlBehavior + " got"); } if (controlBehavior == 1 && warmUpPeriodSec == null) { return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1"); } if (controlBehavior == 2 && maxQueueingTimeMs == null) { return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2"); } entity.setControlBehavior(controlBehavior); if (warmUpPeriodSec != null) { entity.setWarmUpPeriodSec(warmUpPeriodSec); } if (maxQueueingTimeMs != null) { entity.setMaxQueueingTimeMs(maxQueueingTimeMs); } } Date date = new Date(); entity.setGmtModified(date); try { entity = repository.save(entity); if (entity == null) { return Result.ofFail(-1, "save entity fail: null"); } publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get(5000, TimeUnit.MILLISECONDS); return Result.ofSuccess(entity); } catch (Throwable t) { Throwable e = t instanceof ExecutionException ? t.getCause() : t; logger.error("Error when updating flow rules, app={}, ip={}, ruleId={}", entity.getApp(), entity.getIp(), id, e); return Result.ofFail(-1, e.getMessage()); } } @DeleteMapping("/delete.json") @AuthAction(PrivilegeType.WRITE_RULE) public Result<Long> apiDeleteFlowRule(Long id) { if (id == null) { return Result.ofFail(-1, "id can't be null"); } FlowRuleEntity oldEntity = repository.findById(id); if (oldEntity == null) { return Result.ofSuccess(null); } try { repository.delete(id); } catch (Exception e) { return Result.ofFail(-1, e.getMessage()); } try { publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get(5000, TimeUnit.MILLISECONDS); return Result.ofSuccess(id); } catch (Throwable t) { Throwable e = t instanceof ExecutionException ? t.getCause() : t; logger.error("Error when deleting flow rules, app={}, ip={}, id={}", oldEntity.getApp(), oldEntity.getIp(), id, e); return Result.ofFail(-1, e.getMessage()); } } private CompletableFuture<Void> publishRules(String app, String ip, Integer port) { List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port)); // 修改前 // return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules); // 修改后 CompletableFuture<Void> async = sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules); try { if (null != rules) { flowRulePublisher.publish(app, rules); } } catch (Exception e) { logger.error("推送限流策略到Nacos失败, app={}, rule={}", app, rules, e); } return async; } }
6. 熔断规则测试
- Nacos上先克隆备份一下原来配置
- Nacos上原来的配置
- Sentinel控制台
- 修改Sentinel控制台上修改
- 查看Nacos修改后的配置
- 接口设置睡眠100毫秒
- Jmeter压测
- 修改超时为90毫秒再测试
- 添加测试
- 删除测试
7. 限流规则测试
- Nacos上原来的配置
- Sentinel控制台
- 把接口之前设置100毫秒睡眠去掉
- 测试限流6个是否正常
- 修改Sentinel控制台上修改
- 查看Nacos修改后的配置
- Jmeter压测
- 添加测试
- 删除测试
8. 打包使用
- 打包只打控制台包就可以了
- 启动