Sentinel控制台1.8.3修改源码,修改配置后推送到Nacos
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. 打包使用
- 打包只打控制台包就可以了
- 启动
Sentinel控制台1.8.3修改源码,修改配置后推送到Nacos的更多相关文章
- 阿里Sentinel控制台源码修改-对接Apollo规则持久化
改造背景 前面我们讲解了如何对接Apollo来持久化限流的规则,对接后可以直接通过Apollo的后台进行规则的修改,推送到各个客户端实时生效. 但还有一个问题就是Sentinel控制台没有对接Apol ...
- Android5.1.1 - APK签名校验分析和修改源码绕过签名校验
Android5.1.1 - APK签名校验分析和修改源码绕过签名校验 作者:寻禹@阿里聚安全 APK签名校验分析 找到PackageParser类,该类在文件“frameworks/base/cor ...
- Java学习-039-源码 jar 包的二次开发扩展实例(源码修改)
最近在使用已有的一些 jar 包时,发现有些 jar 包中的一些方法无法满足自己的一些需求,例如返回固定的格式,字符串处理等等,因而需要对原有 jar 文件中对应的 class 文件进行二次开发扩展, ...
- python的paramiko源码修改了一下,写了个操作命令的日志审计 bug修改
python的paramiko源码修改了一下,写了个操作命令的日志审计,但是记录的日志中也将backspace删除键记录成^H这个了,于是改了一下代码,用字符串的特性. 字符串具有列表的特性 > ...
- Android6.0 源码修改之 Contacts应用
一.Contacts应用的主界面和联系人详情界面增加顶部菜单添加退出按钮 通过Hierarchy View 工具可以发现 主界面对应的类为 PeopleActivity 联系人详情界面对应的类为 Qu ...
- Android6.0 源码修改之 仿IOS添加全屏可拖拽浮窗返回按钮
前言 之前写过屏蔽系统导航栏功能的文章,具体可看Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP)/动态显示和隐藏NavigationBar 在某些特殊定制的版本中要求 ...
- Windows7 64位环境6sv2.1大气传输模型修改源码添加国产高分卫星GF-1 GF-2光谱响应支持
下面开始添加国产卫星光谱响应的支持: 以下主要参考文章“6S大气传输模型修改源码添加.自定义卫星光谱响应(以HJ-1B CCD为例)”网址:http://blog.csdn.net/sam92/art ...
- element-ui 修改源码实践 --tranfer
1.element-ui 地址:https://github.com/ElemeFE/element 2.修改elelment-ui版本:2.2.2(请选择和项目相对应的版本) 3.修改内容:穿梭框组 ...
- Android6.0 源码修改之屏蔽导航栏虚拟按键(Home和RecentAPP)/动态显示和隐藏NavigationBar
场景分析, 为了完全实现沉浸式效果,在进入特定的app后可以将导航栏移除,当退出app后再次将导航栏恢复.(下面将采用发送广播的方式来移除和恢复导航栏) ps:不修改源码的情况下,简单的沉浸式效果实现 ...
随机推荐
- 开发工具-Visual Studio / Visual Studio Code 官方下载地址
更新记录 2022年6月10日 完善标题. Visual Studio官方下载地址 https://visualstudio.microsoft.com/ Visual Studio Code官方下载 ...
- TypeScript(4)接口
介绍 TypeScript 的核心原则之一是对值所具有的结构进行类型检查.我们使用接口(Interfaces)来定义对象的类型.接口是对象的状态(属性)和行为(方法)的抽象(描述) 接口初探 声明接口 ...
- 轻松上手Fluentd,结合 Rainbond 插件市场,日志收集更快捷
以往有篇文章介绍 EFK(Kibana + ElasticSearch + Filebeat)的插件日志收集.Filebeat 插件用于转发和集中日志数据,并将它们转发到 Elasticsearch ...
- 关于使用koa 跨域问题你可能会遇到
var cors = require('koa2-cors');// 跨域const allowOrigins = ["http://localhost:8080" // 需要跨域 ...
- 手把手教你实现一个图片压缩工具(Vue与Node的完美配合)
前言 图片压缩对于我们日常生活来讲,是非常实用的一项功能.有时我们会在在线图片压缩网站上进行压缩,有时会在电脑下软件进行压缩.那么我们能不能用前端的知识来自己实现一个图片压缩工具呢?答案是有的.效果展 ...
- SAP MM- BAPI_PO_CHANGE 更新PO version 信息(version management)
目的 Version 信息的Complated 字段,自动打勾 实例程序 *&--------------------------------------------------------- ...
- Leetcode--Last Stone Weight II
Last Stone Weight II 欢迎关注H寻梦人公众号 You are given an array of integers stones where stones[i] is the we ...
- 在两台配置了Win10操作系统的电脑之间直接拷贝文件
前提条件:需要一根网线 每台电脑需手动设置IP地址 设置IP地址随意,示例为:10.10.2.11 和 10.10.2.12 每台电脑需关闭Windows防火墙 测试网络是否连通 方式一 远程桌面连接 ...
- 螣龙安科:威胁研究——与MAZE勒索软件事件相关的策略,技术和程序
至少从2019年5月开始,恶意行为者就一直在积极部署MAZE勒索软件.勒索软件最初是通过垃圾邮件和漏洞利用工具包分发的,后来又转移到妥协后进行部署.根据我们在地下论坛中对涉嫌用户的观察以及整个Mand ...
- MIT 6.824 Llab2B Raft之日志复制
书接上文Raft Part A | MIT 6.824 Lab2A Leader Election. 实验准备 实验代码:git://g.csail.mit.edu/6.824-golabs-2021 ...