架构:
springboot+dubbo+sentinel+nacos+mysql
本文内容:全部配置+代码(伸手党的福利)
一:sentinel持久化到nacos(全部配置)
二:sentinel控制台的改造(全部代码)
设计思路:
a) 实现 readSource 方法将数据源中的原始数据转换成我们可以处理的数据S
b) 提供一个 Converter 来将数据S转换成最终的数据T
c) 将最终的数据T更新到具体的 RuleManager 中去
实现原理:
a) 控制台推送规则到Nacos/远程配置中心
b) Sentinel client 监听Nacos配置变化,更新本地缓存
配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel
流程步骤:
引入依赖:
dubbo服务端引入
```java
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.7.1</version>
</dependency>
<!—这里只是引入springcloud包作为nacos和sentinel连接的桥梁,用springcloud配置文件代替代码,简化代码开发,不与dubbo冲突,而且现在阿里正在逐步将dubbo和springcloud实行整合,是一个发展趋势-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>RELEASE</version>
</dependency>
dubbo服务端配置
```java
application-xxx.properties中增加配置
#jvm启动设置
#-Dproject.name=gh-demo-provide
#-Dcsp.sentinel.api.port=9000
#-Dcsp.sentinel.dashboard.server=127.0.0.1:8085
spring.application.name=gh-demo-provide
#同一服务器项目需要端用端口区分
spring.cloud.sentinel.transport.port=9000
#sentinel控制台地址
spring.cloud.sentinel.transport.dashboard=127.0.0.1:8085
# sentinel dashboard
#流量控制
# nacos的访问地址,我这里是nigix代理nacos的集群地址
spring.cloud.sentinel.datasource.flow.nacos.server-addr=10.151.0.84:8848
#与sentinel控制台的namespeace统一
spring.cloud.sentinel.datasource.flow.nacos.namespace=16b7fa67-d3e0-47e4-bc0d-76056712afc4
#nacos中存储规则的dataId,对于dataId使用了${spring.application.name}变量,这样可以根据应用名来区分不同的规则配置
spring.cloud.sentinel.datasource.flow.nacos.data-id=${spring.application.name}-flow-rules
#nacos中存储规则的groupId
spring.cloud.sentinel.datasource.flow.nacos.group-id=SENTINEL_GROUP
#定义存储的规则类型
# 规则类型,取值见:
# org.springframework.cloud.alibaba.sentinel.datasource.RuleType
spring.cloud.sentinel.datasource.flow.nacos.rule-type=flow
#除流控以外的其他规则配置,可以选择性配置,也就是持久化哪个规则就配哪个
#熔断降级
spring.cloud.sentinel.datasource.degrade.nacos.server-addr=10.151.0.84:8848
spring.cloud.sentinel.datasource.degrade.nacos.namespace=16b7fa67-d3e0-47e4-bc0d-76056712afc4
spring.cloud.sentinel.datasource.degrade.nacos.data-id=${spring.application.name}-degrade-rules
spring.cloud.sentinel.datasource.degrade.nacos.group-id=SENTINEL_GROUP
spring.cloud.sentinel.datasource.degrade.nacos.rule-type=degrade
#系统规则
spring.cloud.sentinel.datasource.system.nacos.server-addr=10.151.0.84:8848
spring.cloud.sentinel.datasource.system.nacos.namespace=16b7fa67-d3e0-47e4-bc0d-76056712afc4
spring.cloud.sentinel.datasource.system.nacos.data-id=${spring.application.name}-system-rules
spring.cloud.sentinel.datasource.system.nacos.group-id=SENTINEL_GROUP
spring.cloud.sentinel.datasource.system.nacos.rule-type=system
#授权规则
spring.cloud.sentinel.datasource.authority.nacos.server-addr=10.151.0.84:8848
spring.cloud.sentinel.datasource.authority.nacos.namespace=16b7fa67-d3e0-47e4-bc0d-76056712afc4
spring.cloud.sentinel.datasource.authority.nacos.data-id=${spring.application.name}-authority-rules
spring.cloud.sentinel.datasource.authority.nacos.group-id=SENTINEL_GROUP
spring.cloud.sentinel.datasource.authority.nacos.rule-type=authority
#热点规则
spring.cloud.sentinel.datasource.param-flow.nacos.server-addr=10.151.0.84:8848
spring.cloud.sentinel.datasource.param-flow.nacos.namespace=16b7fa67-d3e0-47e4-bc0d-76056712afc4
spring.cloud.sentinel.datasource.param-flow.nacos.data-id=${spring.application.name}-param-flow-rules
spring.cloud.sentinel.datasource.param-flow.nacos.group-id=SENTINEL_GROUP
spring.cloud.sentinel.datasource.param-flow.nacos.rule-type=param-flow
改造sentinel控制台:
由于sentinel都将规则内容存入内存中,在重启服务或者5分钟之后,规则将被清除,所有这里修改sentinel控制台,使规则在nacos中实现增删改的储存,实现持久化。
sentinel控制台application.properties中加入:
application.properties中增加配置
server.port=8085
#nacos的集群地址
nacos.address=10.151.0.84:8848
#二选一public为空,namespeace为uuid,这里与dubbo服务一致
#nacos.namespace=
nacos.namespace=16b7fa67-d3e0-47e4-bc0d-76056712afc4
增加指定类 *在rule文件夹下增加nacos文件夹,在nacos文件夹下创建5个规则存储和拉取所需要的class,在nacos文件夹下增加NacosConfig和NacosConfigUtil配置类,在util中增加JSONUtils工具类。
增加类中具体的代码如下:
JSONUtils
public class JSONUtils {
public static <T> String toJSONString(Object object) {
try {
return new ObjectMapper().writeValueAsString(object);
} catch (JsonProcessingException e) {
throw new IllegalArgumentException(e);
}
}
public static JavaType getCollectionType(Class<?> collectionClass, Class<?>... elementClasses) {
return new ObjectMapper()
.getTypeFactory()
.constructParametricType(collectionClass, elementClasses);
}
public static <T> List<T> parseObject(Class<T> clazz, String string) {
JavaType javaType = getCollectionType(ArrayList.class, clazz);
try {
return (List<T>) new ObjectMapper().readValue(string, javaType);
} catch (IOException e) {
throw new IllegalArgumentException(e);
}
}
}
NacosConfig
@Configuration
public class NacosConfig {
@Value("${nacos.address}")
private String address;
@Value("${nacos.namespace}")
private String namespace;
@Bean
public ConfigService nacosConfigService() throws Exception {
Properties properties = new Properties();
//nacos集群地址
properties.put(PropertyKeyConst.SERVER_ADDR,address);
//namespace为空即为public
properties.put(PropertyKeyConst.NAMESPACE,namespace);
return ConfigFactory.createConfigService(properties);
}
}
NacosConfigUtil
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 SYSTEM_DATA_ID_POSTFIX = "-system-rules";
public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-param-flow-rules";
public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
public static final String DASHBOARD_POSTFIX = "-sentinel-dashboard";
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() {}
/**
*
* 将规则序列化成JSON文本,存储到Nacos server中
*
* @param configService nacos config service
* @param app 应用名称
* @param postfix 规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX
* @param rules 规则对象
* @throws NacosException 异常
*/
public static <T> void setRuleStringToNacos(ConfigService configService, String app, String postfix, List<T> rules) throws NacosException {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
List<Rule> ruleForApp = rules.stream()
.map(rule -> {
RuleEntity rule1 = (RuleEntity) rule;
System.out.println(rule1.getClass());
Rule rule2 = rule1.toRule();
System.out.println(rule2.getClass());
return rule2;
})
.collect(Collectors.toList());
String dataId = genDataId(app, postfix);
/**
* 俩种存储只是入参不同,为了满足功能的实现,存入nacos后,会有俩个配置,以后继续完善
*/
// 存储,控制微服务使用,即可以起到拦截作用,但是由于无法显示到控制台
configService.publishConfig(
dataId,
NacosConfigUtil.GROUP_ID,
JSONUtils.toJSONString(ruleForApp)
);
// 存储,给控制台显示使用,由于数据太多,会出现转化异常,虽然可以提供控制台显示,但是无法对微服务进行保护
configService.publishConfig(
dataId + DASHBOARD_POSTFIX,
NacosConfigUtil.GROUP_ID,
JSONUtils.toJSONString(rules)
);
}
/**
*
* 从Nacos server中查询响应规则,并将其反序列化成对应Rule实体
*
* @param configService nacos config service
* @param appName 应用名称
* @param postfix 规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX
* @param clazz 类
* @param <T> 泛型
* @return 规则对象列表
* @throws NacosException 异常
*/
public static <T> List<T> getRuleEntitiesFromNacos(ConfigService configService, String appName, String postfix, Class<T> clazz) throws NacosException {
String rules = configService.getConfig(
genDataId(appName, postfix) + DASHBOARD_POSTFIX,
NacosConfigUtil.GROUP_ID,
3000
);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return JSONUtils.parseObject(clazz, rules);
}
private static String genDataId(String appName, String postfix) {
return appName + postfix;
}
}
AuthorityRuleNacosProvider
@Component("authorityRuleNacosProvider")
public class AuthorityRuleNacosProvider implements DynamicRuleProvider<List<AuthorityRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public List<AuthorityRuleEntity> getRules(String appName) throws Exception {
return NacosConfigUtil.getRuleEntitiesFromNacos(
this.configService,
appName,
NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
AuthorityRuleEntity.class
);
}
}
AuthorityRuleNacosPublisher
@Component("authorityRuleNacosPublisher")
public class AuthorityRuleNacosPublisher implements DynamicRulePublisher<List<AuthorityRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public void publish(String app, List<AuthorityRuleEntity> rules) throws Exception {
NacosConfigUtil.setRuleStringToNacos(
this.configService,
app,
NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
rules
);
}
}
DegradeRuleNacosProvider
@Component("degradeRuleNacosProvider")
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public List<DegradeRuleEntity> getRules(String appName) throws Exception {
return NacosConfigUtil.getRuleEntitiesFromNacos(
this.configService,
appName,
NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
DegradeRuleEntity.class
);
}
}
DegradeRuleNacosPublisher
@Component("degradeRuleNacosPublisher")
public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public void publish(String app, List<DegradeRuleEntity> rules) throws Exception {
NacosConfigUtil.setRuleStringToNacos(
this.configService,
app,
NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
rules
);
}
}
FlowRuleNacosProvider
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public List<FlowRuleEntity> getRules(String appName) throws Exception {
return NacosConfigUtil.getRuleEntitiesFromNacos(
this.configService,
appName,
NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
FlowRuleEntity.class
);
}
}
FlowRuleNacosPublisher
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
NacosConfigUtil.setRuleStringToNacos(
this.configService,
app,
NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
rules
);
}
}
ParamFlowRuleNacosProvider
@Component("paramFlowRuleNacosProvider")
public class ParamFlowRuleNacosProvider implements DynamicRuleProvider<List<ParamFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public List<ParamFlowRuleEntity> getRules(String appName) throws Exception {
return NacosConfigUtil.getRuleEntitiesFromNacos(
this.configService,
appName,
NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,
ParamFlowRuleEntity.class
);
}
}
ParamFlowRuleNacosPublisher
@Component("paramFlowRuleNacosPublisher")
public class ParamFlowRuleNacosPublisher implements DynamicRulePublisher<List<ParamFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public void publish(String app, List<ParamFlowRuleEntity> rules) throws Exception {
NacosConfigUtil.setRuleStringToNacos(
this.configService,
app,
NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,
rules
);
}
}
SystemRuleNacosProvider
@Component("systemRuleNacosProvider")
public class SystemRuleNacosProvider implements DynamicRuleProvider<List<SystemRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public List<SystemRuleEntity> getRules(String appName) throws Exception {
return NacosConfigUtil.getRuleEntitiesFromNacos(
this.configService,
appName,
NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,
SystemRuleEntity.class
);
}
}
SystemRuleNacosPublisher
@Component("systemRuleNacosPublisher")
public class SystemRuleNacosPublisher implements DynamicRulePublisher<List<SystemRuleEntity>> {
@Autowired
private ConfigService configService;
@Override
public void publish(String app, List<SystemRuleEntity> rules) throws Exception {
NacosConfigUtil.setRuleStringToNacos(
this.configService,
app,
NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,
rules
);
}
}
*修改5种规则crud的controller层 主要修改数据的存储,将原来存入内存的规则,现在存入nacos,并将nacos的数据push到sentinel的数据源中。
AuthorityRuleController
@RestController
@RequestMapping(value = "/authority")
public class AuthorityRuleController {
private final Logger logger = LoggerFactory.getLogger(AuthorityRuleController.class);
@Autowired
@Qualifier("authorityRuleNacosProvider")
private DynamicRuleProvider<List<AuthorityRuleEntity>> ruleProvider;
@Autowired
@Qualifier("authorityRuleNacosPublisher")
private DynamicRulePublisher<List<AuthorityRuleEntity>> rulePublisher;
/* @Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
private RuleRepository<AuthorityRuleEntity, Long> repository;
@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");
}
try {
// List<AuthorityRuleEntity> rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
List<AuthorityRuleEntity> rules = ruleProvider.getRules(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 <R> Result<R> checkEntityInternal(AuthorityRuleEntity 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 (StringUtil.isBlank(entity.getLimitApp())) {
return Result.ofFail(-1, "limitApp should be valid");
}
if (entity.getStrategy() != RuleConstant.AUTHORITY_WHITE
&& entity.getStrategy() != RuleConstant.AUTHORITY_BLACK) {
return Result.ofFail(-1, "Unknown strategy (must be blacklist or whitelist)");
}
return null;
}
@PostMapping("/rule")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<AuthorityRuleEntity> apiAddAuthorityRule(@RequestBody AuthorityRuleEntity entity) {
Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
entity.setId(null);
Date date = new Date();
entity.setGmtCreate(date);
entity.setGmtModified(date);
try {
entity = repository.save(entity);
publishRules(entity.getApp());
} catch (Throwable throwable) {
logger.error("Failed to add flow rule", throwable);
return Result.ofThrowable(-1, throwable);
}
return Result.ofSuccess(entity);
}
@PutMapping("/rule/{id}")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<AuthorityRuleEntity> apiUpdateParamFlowRule(@PathVariable("id") Long id,
@RequestBody AuthorityRuleEntity entity) {
if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id");
}
Result<AuthorityRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
entity.setId(id);
Date date = new Date();
entity.setGmtCreate(null);
entity.setGmtModified(date);
try {
entity = repository.save(entity);
if (entity == null) {
return Result.ofFail(-1, "Failed to save authority rule");
}
publishRules(entity.getApp());
} catch (Throwable throwable) {
logger.error("Failed to save authority rule", throwable);
return Result.ofThrowable(-1, throwable);
}
return Result.ofSuccess(entity);
}
@DeleteMapping("/rule/{id}")
@AuthAction(PrivilegeType.DELETE_RULE)
public Result<Long> apiDeleteRule(@PathVariable("id") Long id) {
if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id");
}
AuthorityRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null) {
return Result.ofSuccess(null);
}
try {
repository.delete(id);
publishRules(oldEntity.getApp());
} catch (Exception e) {
return Result.ofFail(-1, e.getMessage());
}
return Result.ofSuccess(id);
}
/* private boolean publishRules(String app, String ip, Integer port) {
List<AuthorityRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
}*/
private void publishRules(String app) throws Exception {
List<AuthorityRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
}
DegradeController
@Controller
@RequestMapping(value = "/degrade", produces = MediaType.APPLICATION_JSON_VALUE)
public class DegradeController {
private final Logger logger = LoggerFactory.getLogger(DegradeController.class);
@Autowired
private InMemDegradeRuleStore repository;
@Autowired
@Qualifier("degradeRuleNacosProvider")
private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;
@Autowired
@Qualifier("degradeRuleNacosPublisher")
private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;
/*@Autowired
private SentinelApiClient sentinelApiClient;*/
@ResponseBody
@RequestMapping("/rules.json")
@AuthAction(PrivilegeType.READ_RULE)
public Result<List<DegradeRuleEntity>> queryMachineRules(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);
//去nacos中取数据
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);
}
}
@ResponseBody
@RequestMapping("/new.json")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<DegradeRuleEntity> add(String app, String ip, Integer port, String limitApp, String resource,
Double count, Integer timeWindow, Integer grade) {
if (StringUtil.isBlank(app)) {
return Result.ofFail(-1, "app can't be null or empty");
}
if (StringUtil.isBlank(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 (StringUtil.isBlank(limitApp)) {
return Result.ofFail(-1, "limitApp can't be null or empty");
}
if (StringUtil.isBlank(resource)) {
return Result.ofFail(-1, "resource can't be null or empty");
}
if (count == null) {
return Result.ofFail(-1, "count can't be null");
}
if (timeWindow == null) {
return Result.ofFail(-1, "timeWindow can't be null");
}
if (grade == null) {
return Result.ofFail(-1, "grade can't be null");
}
if (grade < RuleConstant.DEGRADE_GRADE_RT || grade > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
return Result.ofFail(-1, "Invalid grade: " + grade);
}
DegradeRuleEntity entity = new DegradeRuleEntity();
entity.setApp(app.trim());
entity.setIp(ip.trim());
entity.setPort(port);
entity.setLimitApp(limitApp.trim());
entity.setResource(resource.trim());
entity.setCount(count);
entity.setTimeWindow(timeWindow);
entity.setGrade(grade);
Date date = new Date();
entity.setGmtCreate(date);
entity.setGmtModified(date);
try {
entity = repository.save(entity);
//推送信息
publishRules(app);
} catch (Throwable throwable) {
logger.error("add error:", throwable);
return Result.ofThrowable(-1, throwable);
}
/* if (!publishRules(app, ip, port)) {
logger.info("publish degrade rules fail after rule add");
}*/
return Result.ofSuccess(entity);
}
@ResponseBody
@RequestMapping("/save.json")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<DegradeRuleEntity> updateIfNotNull(Long id, String app, String limitApp, String resource,
Double count, Integer timeWindow, Integer grade) {
if (id == null) {
return Result.ofFail(-1, "id can't be null");
}
if (grade != null) {
if (grade < RuleConstant.DEGRADE_GRADE_RT || grade > RuleConstant.DEGRADE_GRADE_EXCEPTION_COUNT) {
return Result.ofFail(-1, "Invalid grade: " + grade);
}
}
DegradeRuleEntity 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 (count != null) {
entity.setCount(count);
}
if (timeWindow != null) {
entity.setTimeWindow(timeWindow);
}
if (grade != null) {
entity.setGrade(grade);
}
Date date = new Date();
entity.setGmtModified(date);
try {
entity = repository.save(entity);
//推送规则
publishRules(entity.getApp());
} catch (Throwable throwable) {
logger.error("save error:", throwable);
return Result.ofThrowable(-1, throwable);
}
/* if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
logger.info("publish degrade rules fail after rule update");
}*/
return Result.ofSuccess(entity);
}
@ResponseBody
@RequestMapping("/delete.json")
@AuthAction(PrivilegeType.DELETE_RULE)
public Result<Long> delete(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("delete error:", throwable);
return Result.ofThrowable(-1, throwable);
}
/* if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
logger.info("publish degrade rules fail after rule delete");
}*/
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(String app) throws Exception {
List<DegradeRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
}
FlowControllerV1
@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("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) {
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);
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 <R> Result<R> checkEntityInternal(FlowRuleEntity entity) {
if (entity == null) {
return Result.ofFail(-1, "invalid 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) {
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());
} catch (Throwable throwable) {
logger.error("Failed to add flow rule", throwable);
return Result.ofThrowable(-1, throwable);
}
return Result.ofSuccess(entity);
}
@PutMapping("/save.json")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<FlowRuleEntity> apiUpdateFlowRule(@PathVariable("id") Long id,
@RequestBody FlowRuleEntity entity) {
if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id");
}
FlowRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null) {
return Result.ofFail(-1, "id " + id + " does not exist");
}
if (entity == null) {
return Result.ofFail(-1, "invalid body");
}
entity.setApp(oldEntity.getApp());
entity.setIp(oldEntity.getIp());
entity.setPort(oldEntity.getPort());
Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);
if (checkResult != null) {
return checkResult;
}
entity.setId(id);
Date date = new Date();
entity.setGmtCreate(oldEntity.getGmtCreate());
entity.setGmtModified(date);
try {
entity = repository.save(entity);
if (entity == null) {
return Result.ofFail(-1, "save entity fail");
}
publishRules(oldEntity.getApp());
} catch (Throwable throwable) {
logger.error("Failed to update flow rule", throwable);
return Result.ofThrowable(-1, throwable);
}
return Result.ofSuccess(entity);
}
@DeleteMapping("/delete.json")
@AuthAction(PrivilegeType.DELETE_RULE)
public Result<Long> apiDeleteFlowRule(Long id) {
if (id == null || id <= 0) {
return Result.ofFail(-1, "Invalid id");
}
FlowRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null) {
return Result.ofSuccess(null);
}
try {
repository.delete(id);
publishRules(oldEntity.getApp());
} catch (Exception e) {
return Result.ofFail(-1, e.getMessage());
}
return Result.ofSuccess(id);
}
/* 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);
}*/
private void publishRules(/*@NonNull*/ String app) throws Exception {
List<FlowRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
}
ParamFlowRuleController
@RestController
@RequestMapping(value = "/paramFlow")
public class ParamFlowRuleController {
private final Logger logger = LoggerFactory.getLogger(ParamFlowRuleController.class);
/* @Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
@Qualifier("paramFlowRuleNacosProvider")
private DynamicRuleProvider<List<ParamFlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("paramFlowRuleNacosPublisher")
private DynamicRulePublisher<List<ParamFlowRuleEntity>> rulePublisher;
@Autowired
private AppManagement appManagement;
@Autowired
private RuleRepository<ParamFlowRuleEntity, Long> repository;
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 (!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(), entity.getIp(), entity.getPort()).get();
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(), entity.getIp(), entity.getPort()).get();
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(), oldEntity.getIp(), oldEntity.getPort()).get();
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(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);
}
SystemController
@RestController
@RequestMapping("/system")
public class SystemController {
private final Logger logger = LoggerFactory.getLogger(SystemController.class);
@Autowired
private RuleRepository<SystemRuleEntity, Long> repository;
@Autowired
@Qualifier("systemRuleNacosProvider")
private DynamicRuleProvider<List<SystemRuleEntity>> ruleProvider;
@Autowired
@Qualifier("systemRuleNacosPublisher")
private DynamicRulePublisher<List<SystemRuleEntity>> rulePublisher;
/* @Autowired
private SentinelApiClient sentinelApiClient;*/
private <R> Result<R> checkBasicParams(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 (port <= 0 || port > 65535) {
return Result.ofFail(-1, "port should be in (0, 65535)");
}
return null;
}
@GetMapping("/rules.json")
@AuthAction(PrivilegeType.READ_RULE)
public Result<List<SystemRuleEntity>> apiQueryMachineRules(String app, String ip,
Integer port) {
Result<List<SystemRuleEntity>> checkResult = checkBasicParams(app, ip, port);
if (checkResult != null) {
return checkResult;
}
try {
// List<SystemRuleEntity> rules = sentinelApiClient.fetchSystemRuleOfMachine(app, ip, port);
List<SystemRuleEntity> rules = ruleProvider.getRules(app);
rules = repository.saveAll(rules);
return Result.ofSuccess(rules);
} catch (Throwable throwable) {
logger.error("Query machine system rules error", throwable);
return Result.ofThrowable(-1, throwable);
}
}
private int countNotNullAndNotNegative(Number... values) {
int notNullCount = 0;
for (int i = 0; i < values.length; i++) {
if (values[i] != null && values[i].doubleValue() >= 0) {
notNullCount++;
}
}
return notNullCount;
}
@RequestMapping("/new.json")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<SystemRuleEntity> apiAdd(String app, String ip, Integer port,
Double highestSystemLoad, Double highestCpuUsage, Long avgRt,
Long maxThread, Double qps) {
Result<SystemRuleEntity> checkResult = checkBasicParams(app, ip, port);
if (checkResult != null) {
return checkResult;
}
int notNullCount = countNotNullAndNotNegative(highestSystemLoad, avgRt, maxThread, qps, highestCpuUsage);
if (notNullCount != 1) {
return Result.ofFail(-1, "only one of [highestSystemLoad, avgRt, maxThread, qps,highestCpuUsage] "
+ "value must be set > 0, but " + notNullCount + " values get");
}
if (null != highestCpuUsage && highestCpuUsage > 1) {
return Result.ofFail(-1, "highestCpuUsage must between [0.0, 1.0]");
}
SystemRuleEntity entity = new SystemRuleEntity();
entity.setApp(app.trim());
entity.setIp(ip.trim());
entity.setPort(port);
// -1 is a fake value
if (null != highestSystemLoad) {
entity.setHighestSystemLoad(highestSystemLoad);
} else {
entity.setHighestSystemLoad(-1D);
}
if (null != highestCpuUsage) {
entity.setHighestCpuUsage(highestCpuUsage);
} else {
entity.setHighestCpuUsage(-1D);
}
if (avgRt != null) {
entity.setAvgRt(avgRt);
} else {
entity.setAvgRt(-1L);
}
if (maxThread != null) {
entity.setMaxThread(maxThread);
} else {
entity.setMaxThread(-1L);
}
if (qps != null) {
entity.setQps(qps);
} else {
entity.setQps(-1D);
}
Date date = new Date();
entity.setGmtCreate(date);
entity.setGmtModified(date);
try {
entity = repository.save(entity);
//推送
publishRules(app);
} catch (Throwable throwable) {
logger.error("Add SystemRule error", throwable);
return Result.ofThrowable(-1, throwable);
}
/* if (!publishRules(app, ip, port)) {
logger.warn("Publish system rules fail after rule add");
}*/
return Result.ofSuccess(entity);
}
@GetMapping("/save.json")
@AuthAction(PrivilegeType.WRITE_RULE)
public Result<SystemRuleEntity> apiUpdateIfNotNull(Long id, String app, Double highestSystemLoad,
Double highestCpuUsage, Long avgRt, Long maxThread, Double qps) {
if (id == null) {
return Result.ofFail(-1, "id can't be null");
}
SystemRuleEntity 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 (highestSystemLoad != null) {
if (highestSystemLoad < 0) {
return Result.ofFail(-1, "highestSystemLoad must >= 0");
}
entity.setHighestSystemLoad(highestSystemLoad);
}
if (highestCpuUsage != null) {
if (highestCpuUsage < 0) {
return Result.ofFail(-1, "highestCpuUsage must >= 0");
}
if (highestCpuUsage > 1) {
return Result.ofFail(-1, "highestCpuUsage must <= 1");
}
entity.setHighestCpuUsage(highestCpuUsage);
}
if (avgRt != null) {
if (avgRt < 0) {
return Result.ofFail(-1, "avgRt must >= 0");
}
entity.setAvgRt(avgRt);
}
if (maxThread != null) {
if (maxThread < 0) {
return Result.ofFail(-1, "maxThread must >= 0");
}
entity.setMaxThread(maxThread);
}
if (qps != null) {
if (qps < 0) {
return Result.ofFail(-1, "qps must >= 0");
}
entity.setQps(qps);
}
Date date = new Date();
entity.setGmtModified(date);
try {
entity = repository.save(entity);
//推送
publishRules(entity.getApp());
} catch (Throwable throwable) {
logger.error("save error:", throwable);
return Result.ofThrowable(-1, throwable);
}
/* if (!publishRules(entity.getApp(), entity.getIp(), entity.getPort())) {
logger.info("publish system rules fail after rule update");
}*/
return Result.ofSuccess(entity);
}
@RequestMapping("/delete.json")
@AuthAction(PrivilegeType.DELETE_RULE)
public Result<?> delete(Long id) {
if (id == null) {
return Result.ofFail(-1, "id can't be null");
}
SystemRuleEntity oldEntity = repository.findById(id);
if (oldEntity == null) {
return Result.ofSuccess(null);
}
try {
repository.delete(id);
//推送
publishRules(oldEntity.getApp());
} catch (Throwable throwable) {
logger.error("delete error:", throwable);
return Result.ofThrowable(-1, throwable);
}
/* if (!publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort())) {
logger.info("publish system rules fail after rule delete");
}*/
return Result.ofSuccess(id);
}
/* private boolean publishRules(String app, String ip, Integer port) {
List<SystemRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
return sentinelApiClient.setSystemRuleOfMachine(app, ip, port, rules);
}*/
private void publishRules(String app) throws Exception {
List<SystemRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
}
控制台改造完成
Sentinel中加入规则
查看nacos中已经存入
若nacos用到了mysql,查看数据库
完成了sentinel->nacos->mysql->nacos->sentinel