Sentinel规则持久化到Nacos及规则数据双向同步
Sentinel规则持久化到Nacos及规则数据双向同步
说明:此处Sentinel网关规则持久化是使用推模式扩展,将Sentinel网关规则持久化到Nacos,至于持久化到
1.1、版本说明
Spring Cloud Alibaba Version:2.2.7.RELEASE
Sentinel Version:1.8.1
1.2、源码下载
源码地址如下,点击Tags选择版本为1.8.1,然后点击下载ZIP压缩包,下载地址如下:
https://github.com/alibaba/Sentinel/tree/1.8.1
2.1、pom依赖修改和导入
<!-- 找到Sentinel持久化到Nacos数据源,将scope注释掉,如下所示 -->
<!-- for Nacos rule publisher sample -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<!--<scope>test</scope>-->
</dependency>
<!-- 导入下面依赖, 方便后续改造使用 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.11</version>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.22</version>
</dependency>
<dependency>
<groupId>com.alibaba.nacos</groupId>
<artifactId>nacos-client</artifactId>
<version>2.0.3</version>
</dependency>
在src/main/resources/application.properties配置文件中添加nacos配置,如下所示
# nacos settings
# nacos地址根据项目中nacos服务的地址配置
nacos.address=127.0.0.1:8848
# 如果有单独的命名空间添加此配置, 没有就不设置
nacos.namespace=35788967-0687-4f5e-a53e-88fe25e59266
nacos.username=nacos
nacos.password=nacos
2.3、创建Nacos配置类
2.4、修改Nacos配置类
2.4.1、修改NacosConfig类
NacosConfig配置类修改如下,主要是添加规则和创建Nacos配置服务,NacosConfig配置类修改后代码如下
package com.alibaba.csp.sentinel.dashboard.rule.nacos;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.*;
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.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.List;
import java.util.Properties;
/**
* @author 星空流年
*/
@Configuration
public class NacosConfig {
@Value("${nacos.address}")
private String address;
@Value("${nacos.namespace}")
private String namespace;
@Value("${nacos.username}")
private String username;
@Value("${nacos.password}")
private String password;
/**
* 流控规则
*
* @return
*/
@Bean
public Converter<List<FlowRuleEntity>, String> flowRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
return s -> JSON.parseArray(s, FlowRuleEntity.class);
}
/**
* 授权规则
*
* @return
*/
@Bean
public Converter<List<AuthorityRuleEntity>, String> authorRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<AuthorityRuleEntity>> authorRuleEntityDecoder() {
return s -> JSON.parseArray(s, AuthorityRuleEntity.class);
}
/**
* 降级规则
*
* @return
*/
@Bean
public Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
return s -> JSON.parseArray(s, DegradeRuleEntity.class);
}
/**
* 热点规则
*
* @return
*/
@Bean
public Converter<List<ParamFlowRuleEntity>, String> paramRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<ParamFlowRuleEntity>> paramRuleEntityDecoder() {
return s -> JSON.parseArray(s, ParamFlowRuleEntity.class);
}
/**
* 系统规则
*
* @return
*/
@Bean
public Converter<List<SystemRuleEntity>, String> systemRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<SystemRuleEntity>> systemRuleEntityDecoder() {
return s -> JSON.parseArray(s, SystemRuleEntity.class);
}
/**
* 网关API分组管理规则
*
* @return
* @throws Exception
*/
@Bean
public Converter<List<ApiDefinitionEntity>, String> apiDefinitionEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<ApiDefinitionEntity>> apiDefinitionEntityDecoder() {
return s -> JSON.parseArray(s, ApiDefinitionEntity.class);
}
/**
* 网关流控规则
*
* @return
* @throws Exception
*/
@Bean
public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder() {
return s -> JSON.parseArray(s, GatewayFlowRuleEntity.class);
}
/**
* nacos配置服务
*
* @return
* @throws Exception
*/
@Bean
public ConfigService nacosConfigService() throws Exception {
Properties properties = new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, address);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
properties.put(PropertyKeyConst.USERNAME, username);
properties.put(PropertyKeyConst.PASSWORD, password);
return ConfigFactory.createConfigService(properties);
}
}
2.4.2、修改NacosConfigUtil类
NacosConfigUtil工具类修改如下,主要是添加规则常量,添加内容如下
/** 流控规则 */
public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";
/** 系统保护规则 */
public static final String SYSTEM_DATA_ID_POSTFIX = "-system-rules";
/** 访问控制规则 */
public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
/** 网关流控规则 */
public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "-gw-flow-rules";
/** 网关API分组管理规则 */
public static final String GATEWAY_API_DATA_ID_POSTFIX = "-gw-api-group-rules";
添加效果如下图所示:
2.5、创建网关规则目录类
2.5.1、GatewayApiNacosProvider类
GatewayApiNacosProvider类:主要是拉取Nacos中手动添加的API分组管理配置信息,类代码如下
package com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.api;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 拉取Nacos中存储的网关分组管理规则配置信息
*
* @author 星空流年
*/
@Component("gatewayApiNacosProvider")
public class GatewayApiNacosProvider implements DynamicRuleProvider<List<ApiDefinitionEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<ApiDefinitionEntity>> converter;
@Override
public List<ApiDefinitionEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX, NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
2.5.2、GatewayApiNacosPublisher类
GatewayApiNacosPublisher类:主要是推送网关分组管理规则持久化到Nacos中
package com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.api;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.ApiDefinitionEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 推送网关分组管理规则持久化到Nacos中
*
* @author 星空流年
*/
@Component("gatewayApiNacosPublisher")
public class GatewayApiNacosPublisher implements DynamicRulePublisher<List<ApiDefinitionEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<ApiDefinitionEntity>, String> converter;
@Override
public void publish(String app, List<ApiDefinitionEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app + NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());
}
}
package com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.flow;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* 拉取Nacos中存储的网关流控规则配置信息
*
* @author 星空流年
*/
@Component("gatewayFlowRulesNacosProvider")
public class GatewayFlowRulesNacosProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<GatewayFlowRuleEntity>> converter;
@Override
public List<GatewayFlowRuleEntity> getRules(String app) throws Exception {
String rules = configService.getConfig(app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.nacos.gateway.flow;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.gateway.GatewayFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* 推送网关流控规则持久化到Nacos中
*
* @author 星空流年
*/
@Component("gatewayFlowRulesNacosPublisher")
public class GatewayFlowRulesNacosPunlisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<GatewayFlowRuleEntity>, String> converter;
@Override
public void publish(String app, List<GatewayFlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());
}
}
2.6、修改GatewayApiController接口
GatewayApiController类所在路径:src/main/java/com/alibaba/csp/sentinel/dashboard/controller/gateway/GatewayApiController.java
主要包含以下接口:
URL
|
方法名
|
请求方式
|
接口说明
|
---|---|---|---|
/gateway/api/list.json
|
queryApis
|
GET
|
获取所有的API分组管理规则列表
|
/gateway/api/new.json
|
addApi
|
POST
|
新增API分组
|
/gateway/api/save.json
|
updateApi
|
POST
|
修改当前存在的API分组信息
|
/gateway/api/delete.json
|
deleteApi
|
POST
|
删除一条API分组信息
|
修改GatewayApiController接口就是对上面所列接口进行改造,将其从内存中获取规则的方式修改为从nacos中获取,同时将其持久化方式由持久化到内存修改为持久化到nacos。具体修改如下:
/*@Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
@Qualifier("gatewayApiNacosProvider")
private DynamicRuleProvider<List<ApiDefinitionEntity>> ruleProvider;
@Autowired
@Qualifier("gatewayApiNacosPublisher")
private DynamicRulePublisher<List<ApiDefinitionEntity>> rulePublisher;
说明:
SentinelApiClient类主要负责与
2.6.2、修改queryApis方法
修改地方如图所示:
修改之后的代码如下:
代码如下:
import cn.hutool.core.collection.CollectionUtil;
@GetMapping("/list.json")
@AuthAction(AuthService.PrivilegeType.READ_RULE)
public Result<List<ApiDefinitionEntity>> queryApis(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<ApiDefinitionEntity> apis = ruleProvider.getRules(app);
if (CollectionUtil.isNotEmpty(apis)) {
for (ApiDefinitionEntity rule : apis) {
rule.setApp(app.trim());
rule.setIp(ip);
rule.setPort(port);
}
repository.saveAll(apis);
}
return Result.ofSuccess(apis);
} catch (Throwable throwable) {
logger.error("queryApis error:", throwable);
return Result.ofThrowable(-1, throwable);
}
}
2.6.3、修改addApi方法
修改地方如图所示:
修改效果如下:
代码如下:
try {
// 设置ID
List<ApiDefinitionEntity> rules = ruleProvider.getRules(entity.getApp());
if (CollectionUtil.isNotEmpty(rules)) {
Optional<ApiDefinitionEntity> apiRule = rules.stream().max(Comparator.comparingLong(ApiDefinitionEntity::getId));
entity.setId(apiRule.get().getId() + 1L);
}
entity = repository.save(entity);
} catch (Throwable throwable) {
logger.error("add gateway api error:", throwable);
return Result.ofThrowable(-1, throwable);
}
publishApis(app);
改造之后的publishApis()方法如下:
代码如下:
/**
* 将API分组管理规则推送到Nacos
*
* @param app
*/
private void publishApis(String app) {
List<ApiDefinitionEntity> apis = repository.findAllByApp(app);
try {
rulePublisher.publish(app, apis);
} catch (Exception e) {
logger.warn("publish gateway apis fail, the exception is {}", e);
}
}
修改地方如下:
修改效果如下:
代码如下:
publishApis(app);
2.6.5、修改deleteApi方法
修改地方如下:
修改效果如下:
代码如下:
publishApis(oldEntity.getApp());
GatewayFlowRuleController类所在路径:src/main/java/com/alibaba/csp/sentinel/dashboard/controller/gateway/GatewayFlowRuleController.java
主要包含以下接口:
URL
|
方法名
|
请求方式
|
接口说明
|
---|---|---|---|
/gateway/flow/list.json
|
queryFlowRules
|
GET
|
获取所有的网关流控规则列表
|
/gateway/flow/new.json
|
addFlowRule
|
POST
|
新增网关流控规则
|
/gateway/flow/save.json
|
updateFlowRule
|
POST
|
修改当前存在的网关流控规则
|
/gateway/flow/delete.json
|
deleteFlowRule
|
POST
|
删除一条网关流控规则
|
修改GatewayFlowRuleController接口就是对上面所列接口进行改造,将其从内存中获取规则的方式修改为从nacos中获取,同时将其持久化方式由持久化到内存修改为持久化到nacos。具体修改如下:
2.7.1、修改注入类
/*@Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
@Qualifier("gatewayFlowRulesNacosProvider")
private DynamicRuleProvider<List<GatewayFlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("gatewayFlowRulesNacosPublisher")
private DynamicRulePublisher<List<GatewayFlowRuleEntity>> rulePublisher;
说明:
SentinelApiClient类主要负责与
2.7.2、修改queryFlowRules方法
修改地方如图所示:
修改之后的代码如下:
import cn.hutool.core.collection.CollectionUtil;
import java.util.Objects;
try {
List<GatewayFlowRuleEntity> rules = ruleProvider.getRules(app);
if (CollectionUtil.isNotEmpty(rules)) {
for (GatewayFlowRuleEntity rule : rules) {
rule.setApp(app.trim());
rule.setIp(ip);
rule.setPort(port);
// intervalSec:统计时间窗口,单位是秒,默认是1秒
if (Objects.isNull(rule.getInterval())) {
rule.setInterval(1L);
}
if (Objects.isNull(rule.getIntervalUnit())) {
rule.setIntervalUnit(INTERVAL_UNIT_SECOND);
}
// controlBehavior:流量整型的控制效果,同限流规则的 controlBehavior 字段
// 目前支持快速失败和匀速排队两种模式,默认是快速失败
if (Objects.isNull(rule.getControlBehavior())) {
rule.setControlBehavior(0);
}
// burst:应对突发请求时额外允许的请求数目
if (Objects.isNull(rule.getBurst())) {
rule.setBurst(0);
}
}
repository.saveAll(rules);
}
return Result.ofSuccess(rules);
} catch (Throwable throwable) {
logger.error("query gateway flow rules error:", throwable);
return Result.ofThrowable(-1, throwable);
}
2.7.3、修改addFlowRule方法
修改效果如下:
代码如下:
try {
// 设置ID
List<GatewayFlowRuleEntity> rules = ruleProvider.getRules(entity.getApp());
if (CollectionUtil.isNotEmpty(rules)) {
Optional<GatewayFlowRuleEntity> gatewayFlowRule = rules.stream().max(Comparator.comparingLong(GatewayFlowRuleEntity::getId));
entity.setId(gatewayFlowRule.get().getId() + 1L);
}
entity = repository.save(entity);
} catch (Throwable throwable) {
logger.error("add gateway flow rule error:", throwable);
return Result.ofThrowable(-1, throwable);
}
publishRules(app);
改造之后的publishRules方法如下:代码如下:
/**
* 将网关流控规则推送到Nacos
*
* @param app
*/
private void publishRules(String app) {
List<GatewayFlowRuleEntity> rules = repository.findAllByApp(app);
try {
rulePublisher.publish(app, rules);
} catch (Exception e) {
logger.warn("publish gateway flow rules fail, the exception is {}", e);;
}
}
2.7.4、修改updateFlowRule方法
修改地方如下:
修改效果如下:
代码如下:
publishRules(app);
2.7.5、修改deleteFlowRule方法
修改地方如下:
修改效果如下:
代码如下:
publishRules(oldEntity.getApp());
3、sentinel-dashboard中其他规则持久化改造
说明:关于sentinel其他规则,例如:流控、降级、访问控制、热点规则、系统保护规则等,这部分规则持久化到Nacos的改造在上面目录结构的基础上进行修改。其中这里提到的流控和网关流控规则不一致,至于二者区别,可参看官网文档,地址如下:https://github.com/alibaba/Sentinel/wiki/%E4%BB%8B%E7%BB%8D
3.1、创建其他规则目录类
在 src/main/java/com/alibaba/csp/sentinel/dashboard/rule/nacos 包名下创建如下目录结构
3.1.1、访问控制规则类代码
3.1.1.1、AuthorityRuleNacosProvider类
AuthorityRuleNacosProvider类:主要是拉取Nacos中手动添加的访问控制规则配置信息,类代码如下
package com.alibaba.csp.sentinel.dashboard.rule.nacos.authority;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author 星空流年
*/
@Component("authorityRuleNacosProvider")
public class AuthorityRuleNacosProvider implements DynamicRuleProvider<List<AuthorityRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<AuthorityRuleEntity>> converter;
@Override
public List<AuthorityRuleEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
3.1.1.2、AuthorityRuleNacosPublisher类
AuthorityRuleNacosPublisher类:主要是推送访问控制规则持久化到Nacos中,具体代码如下:
package com.alibaba.csp.sentinel.dashboard.rule.nacos.authority;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.AuthorityRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author 星空流年
*/
@Component("authorityRuleNacosPublisher")
public class AuthorityRuleNacosPublisher implements DynamicRulePublisher<List<AuthorityRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<AuthorityRuleEntity>, String> converter;
@Override
public void publish(String app, List<AuthorityRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app + NacosConfigUtil.AUTHORITY_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());
}
}
3.1.2、降级规则类代码
package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author 星空流年
*/
@Component("degradeRuleNacosProvider")
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<DegradeRuleEntity>> converter;
@Override
public List<DegradeRuleEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.nacos.degrade;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.DegradeRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author 星空流年
*/
@Component("degradeRuleNacosPublisher")
public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<DegradeRuleEntity>, String> converter;
@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(app + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());
}
}
3.1.3、普通流控类代码
3.1.3.1、FlowRuleNacosProvider类
package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author 星空流年
*/
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<FlowRuleEntity>> converter;
@Override
public List<FlowRuleEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.nacos.flow;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author 星空流年
*/
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<FlowRuleEntity>, String> converter;
@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(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());
}
}
3.1.4、热点规则类代码
3.1.4.1、ParamFlowRuleNacosProvider类
package com.alibaba.csp.sentinel.dashboard.rule.nacos.param;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author 星空流年
*/
@Component("paramFlowRuleNacosProvider")
public class ParamFlowRuleNacosProvider implements DynamicRuleProvider<List<ParamFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<ParamFlowRuleEntity>> converter;
@Override
public List<ParamFlowRuleEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.nacos.param;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.ParamFlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author 星空流年
*/
@Component("paramFlowRuleNacosPublisher")
public class ParamFlowRuleNacosPublisher implements DynamicRulePublisher<List<ParamFlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<ParamFlowRuleEntity>, String> converter;
@Override
public void publish(String app, List<ParamFlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());
}
}
3.1.5.1、SystemRuleNacosProvider类
package com.alibaba.csp.sentinel.dashboard.rule.nacos.system;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.StringUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
/**
* @author 星空流年
*/
@Component("systemRuleNacosProvider")
public class SystemRuleNacosProvider implements DynamicRuleProvider<List<SystemRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<SystemRuleEntity>> converter;
@Override
public List<SystemRuleEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
package com.alibaba.csp.sentinel.dashboard.rule.nacos.system;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.SystemRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.dashboard.rule.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import com.alibaba.nacos.api.config.ConfigType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author 星空流年
*/
@Component("systemRuleNacosPublisher")
public class SystemRuleNacosPublisher implements DynamicRulePublisher<List<SystemRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private Converter<List<SystemRuleEntity>, String> converter;
@Override
public void publish(String app, List<SystemRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
configService.publishConfig(app + NacosConfigUtil.SYSTEM_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules), ConfigType.JSON.getType());
}
}
3.2、修改AuthorityRuleController接口
AuthorityRuleController类所在路径:src/main/java/com/alibaba/csp/sentinel/dashboard/controller/AuthorityRuleController.java
主要包含以下接口:
URL
|
方法名
|
请求方式
|
接口说明
|
---|---|---|---|
/authority/rules
|
apiQueryAllRulesForMachine
|
GET
|
获取所有的访问控制规则列表
|
/authority/rule
|
apiAddAuthorityRule
|
POST
|
新增访问控制规则分组
|
/authority/rule/{id}
|
apiUpdateParamFlowRule
|
PUT
|
修改当前存在的访问控制规则信息
|
/authority/rule/{id}
|
apiDeleteRule
|
DELETE
|
删除一条访问控制规则信息
|
3.2.1、修改注入类
/*@Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
@Qualifier("authorityRuleNacosProvider")
private DynamicRuleProvider<List<AuthorityRuleEntity>> ruleProvider;
@Autowired
@Qualifier("authorityRuleNacosPublisher")
private DynamicRulePublisher<List<AuthorityRuleEntity>> rulePublisher;
代码如下:
List<AuthorityRuleEntity> rules = ruleProvider.getRules(app);
添加代码如下:
publishRules(entity.getApp());
重写的publishRules()方法如下:
代码如下:
private void publishRules(String app) {
List<AuthorityRuleEntity> rules = repository.findAllByApp(app);
try {
rulePublisher.publish(app,rules);
} catch (Exception e) {
logger.warn("publish authority rule fail, the exception is {}", e);
}
}
3.2.4、修改apiUpdateParamFlowRule方法
说明:源码中此方法命名有误,关于错误原因,大家应该能猜出来,如果对此方法名不在意的,不需修改,若是在意,请自行修改,故在此进行说明
添加代码如下:
publishRules(entity.getApp());
添加代码如下:
publishRules(oldEntity.getApp());
3.3、修改DegradeController接口
主要包含以下接口:
URL | 方法名 | 请求方式 | 接口说明 |
---|---|---|---|
/degrade/rules.json | apiQueryMachineRules | GET | 获取所有的降级控制规则列表 |
/degrade/rule | apiAddRule | POST | 新增降级规则分组 |
/degrade/rule/{id} | apiUpdateRule | PUT | 修改当前存在的降级规则信息 |
/degrade/rule/{id} | delete | DELETE | 删除一条降级规则信息 |
/*@Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
@Qualifier("degradeRuleNacosProvider")
private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;
@Autowired
@Qualifier("degradeRuleNacosPublisher")
private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;
添加代码如下:
List<DegradeRuleEntity> rules = ruleProvider.getRules(app);
添加代码如下:
publishRules(entity.getApp());
重写的publishRules()方法如下:
代码如下:
private void publishRules(String app) {
List<DegradeRuleEntity> rules = repository.findAllByApp(app);
try {
rulePublisher.publish(app,rules);
} catch (Exception e) {
logger.warn("publish degrade rule fail, the exception is {}", e);
}
}
添加代码如下:
publishRules(entity.getApp());
添加代码如下:
publishRules(oldEntity.getApp());
3.4、修改FlowControllerV2接口注入
FlowControllerV2类所在路径:src/main/java/com/alibaba/csp/sentinel/dashboard/controller/v2/FlowControllerV2.java
说明:FlowControllerV2类为官方提供的一个参考实例类,针对此类的修改只需要将注入依赖修改为自定义的持久化Nacos类即可。
修改如下:
代码如下:
/*@Autowired
@Qualifier("flowRuleDefaultProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleDefaultPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;*/
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
3.5、修改ParamFlowRuleController接口
ParamFlowRuleController类所在路径:src/main/java/com/alibaba/csp/sentinel/dashboard/controller/ParamFlowRuleController.java
主要包含以下接口:
URL
|
方法名
|
请求方式
|
接口说明
|
---|---|---|---|
/paramFlow/rules
|
apiQueryAllRulesForMachine
|
GET
|
获取所有的热点规则列表
|
/paramFlow/rule
|
apiAddParamFlowRule
|
POST
|
新增热点规则分组
|
/paramFlow/rule/{id}
|
apiUpdateParamFlowRule
|
PUT
|
修改当前存在的热点规则信息
|
/paramFlow/rule/{id}
|
apiDeleteRule
|
DELETE
|
删除一条热点规则信息
|
3.5.1、修改注入类
/*@Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
@Qualifier("paramFlowRuleNacosProvider")
private DynamicRuleProvider<List<ParamFlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("paramFlowRuleNacosPublisher")
private DynamicRulePublisher<List<ParamFlowRuleEntity>> rulePublisher;
3.5.2、修改apiQueryAllRulesForMachine方法
添加代码如下:
List<ParamFlowRuleEntity> rules = ruleProvider.getRules(app);
rules = repository.saveAll(rules);
return Result.ofSuccess(rules);
添加代码如下:
publishRules(entity.getApp());
重写publishRules()方法如下:
代码如下:
private void publishRules(String app) throws Exception {
List<ParamFlowRuleEntity> rules=repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
添加代码如下:
publishRules(entity.getApp());
添加代码如下:
publishRules(oldEntity.getApp());
3.6、修改SystemController接口
SystemController类所在路径:src/main/java/com/alibaba/csp/sentinel/dashboard/controller/SystemController.java
主要包含以下接口:
URL
|
方法名
|
请求方式
|
接口说明
|
---|---|---|---|
/system/rules.json
|
apiQueryMachineRules
|
GET
|
获取所有的系统保护规则列表
|
/system/new.json
|
apiAdd
|
POST
|
新增系统保护规则分组
|
/system/save.json
|
apiUpdateIfNotNull
|
PUT
|
修改当前存在的系统保护规则信息
|
/system/delete.json
|
delete
|
DELETE
|
删除一条系统保护规则信息
|
3.6.1、修改注入类
/*@Autowired
private SentinelApiClient sentinelApiClient;*/
@Autowired
@Qualifier("systemRuleNacosProvider")
private DynamicRuleProvider<List<SystemRuleEntity>> ruleProvider;
@Autowired
@Qualifier("systemRuleNacosPublisher")
private DynamicRulePublisher<List<SystemRuleEntity>> rulePublisher;
添加代码如下:
List<SystemRuleEntity> rules =ruleProvider.getRules(app);
添加代码如下:
publishRules(app);
重写publishRules()方法:
代码如下:
private void publishRules(String app) {
List<SystemRuleEntity> rules = repository.findAllByApp(app);
try {
rulePublisher.publish(app,rules);
} catch (Exception e) {
logger.warn("publish system rule fail, the exception is {}", e);
}
}
添加代码如下:
publishRules(app);
添加代码如下:
publishRules(oldEntity.getApp());
4.1、后端项目启动
在IDE中运行 com.alibaba.csp.sentinel.dashboard.DashboardApplication类启动项目即可
4.2、前端项目启动
2、修改 src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html 页面,将流控规则菜单中的dashboard.flowV1改为dashboard.flow,即可调用V2相关页面和接口
说明:前端项目为angular项目,启动方式可以参看 src/main/webapp/resources/README_zh.md 文档,
针对此错误,可使用如下解决方案:
在package.json文件的同级目录下新建一个npm-shrinkwrap.json文件,如下所示
npm-shrinkwrap.json文件内容如下:
{
"dependencies": {
"graceful-fs": {
"version": "4.2.2"
}
}
}