前面两篇讲了不用springcloud做粘合,直接springboot+dubbo+nacos+sentinel的搭建
这篇讲用springcloud做粘合是怎么搞的
一、springcloud+sentinel
在前面的项目的基础上加入
<!--sentinel 核心环境 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
application.yml加入配置
sentinel:
transport:
port: 8719
dashboard: localhost:8080
代码中用@SentinelResource标记要限流的资源
@RestController
public class AccountController {
@Autowired
AccountService accountService;
@SentinelResource(value = "accountController-get")
@RequestMapping(value = "account/get", method = RequestMethod.GET)
public String get(String userId) throws InterruptedException {
Thread.sleep(1000);
return "done";
}
}
启动后调用一下这个controller这样才能在sentinel界面看到
添加一个流控规则试一下
频繁多点几次就会出现限流
二、springcloud+dubbo+sentinel
前面讲的相当于是直接用springcloud+sentinel,在http接口的地方用@SentinelResource标记资源。
下面讲在dubbo的RPC调用的时候怎么结合springcloud+sentinel用
引入依赖
<!--sentinel 核心环境 依赖-->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
<!-- sentinel与dubbo适配需要的适配 对于 Apache Dubbo 2.7.x 及以上版本-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-apache-dubbo-adapter</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-transport-simple-http</artifactId>
<version>1.7.2</version>
</dependency>
注意要加入sentinel-transport-simlpe-http,不然启动要报错
Exception in thread "Thread-16" java.lang.NoClassDefFoundError: com/alibaba/csp/sentinel/log/CommandCenterLog
启动起来,然后出发一下dubbo的RPC调用。就能在sentinel的控制界面的簇点链路中看到了
三、sentinel配置的规则做持久化
目前这样,sentinel上面配置的流控规则这些,一旦把sentinel重启就会消失。
一般来说,规则的推送有下面三种模式
推送模式 | 说明 | 优点 | 缺点 |
---|---|---|---|
原始模式 | API 将规则推送至客户端并直接更新到内存中,扩展写数据源(WritableDataSource ) | 简单,无任何依赖 | 不保证一致性;规则保存在内存中,重启即消失。严重不建议用于生产环境 |
Pull 模式 | 扩展写数据源(WritableDataSource ), 客户端主动向某个规则管理中心定期轮询拉取规则,这个规则中心可以是 RDBMS、文件 等 | 简单,无任何依赖;规则持久化 | 不保证一致性;实时性不保证,拉取过于频繁也可能会有性能问题。 |
Push 模式 | 扩展读数据源(ReadableDataSource ),规则中心统一推送,客户端通过注册监听器的方式时刻监听变化,比如使用 Nacos、Zookeeper 等配置中心。这种方式有更好的实时性和一致性保证。生产环境下一般采用 push 模式的数据源。 | 规则持久化;一致性;快速 | 引入第三方依赖 |
1.原始模式
如果不做任何修改,Dashboard 的推送规则方式是通过 API 将规则推送至客户端并直接更新到内存中:
这种做法的好处是简单,无依赖;坏处是应用重启规则就会消失,仅用于简单测试,不能用于生产环境。
2.Pull模式
pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。
使用时需要在客户端注册数据源:将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 WritableDataSourceRegistry
中。
原理:
本地文件数据源会定时轮询文件的变更,读取规则。
这样我们既可以在应用本地直接修改文件来更新规则,也可以通过 Sentinel 控制台推送规则。
以本地文件数据源为例,推送过程如下图所示:
首先 Sentinel 控制台通过 API 将规则推送至客户端并更新到内存中,接着注册的写数据源会将新的规则保存到本地的文件中。
使用 pull 模式的数据源时一般不需要对 Sentinel 控制台进行改造。
这种实现方法好处是简单,不引入新的依赖,坏处是无法保证监控数据的一致性。
Pull 优缺点
优点
简单,无任何依赖
没有额外依赖
缺点
不保证一致性(规则是使用FileRefreshableDataSource
定时更新,会有延迟)
实时性不保证(规则是使用FileRefreshableDataSource
定时更新)
拉取过于频繁也可能会有性能问题
由于文件存储于本地,容易丢失
以本地文件数据源为例
在上面已有了的依赖的情况下加入依赖
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-parameter-flow-control</artifactId>
<version>1.7.2</version>
</dependency>
常量类定义规则文件的目录和名字
package com.sid.config;
import java.util.HashMap;
import java.util.Map;
/**
* 常量类,主要是定义规则文件的目录和名字
* */
public class PersistenceRuleConstant {
/**
* 存储文件路径
*/
public static final String storePath = System.getProperty("user.home") + "\\sentinel\\rules\\order-app\\";
/**
* 各种存储sentinel规则映射map
*/
public static final Map<String, String> rulesMap = new HashMap<String, String>();
//流控规则文件
public static final String FLOW_RULE_PATH = "flowRulePath";
//降级规则文件
public static final String DEGRAGE_RULE_PATH = "degradeRulePath";
//授权规则文件
public static final String AUTH_RULE_PATH = "authRulePath";
//系统规则文件
public static final String SYSTEM_RULE_PATH = "systemRulePath";
//热点参数文件
public static final String HOT_PARAM_RULE = "hotParamRulePath";
static {
rulesMap.put(FLOW_RULE_PATH, storePath + "flowRule.json");
rulesMap.put(DEGRAGE_RULE_PATH, storePath + "degradeRule.json");
rulesMap.put(SYSTEM_RULE_PATH, storePath + "systemRule.json");
rulesMap.put(AUTH_RULE_PATH, storePath + "authRule.json");
rulesMap.put(HOT_PARAM_RULE, storePath + "hotParamRule.json");
}
}
文件操作类:如果规则文件不存在就创建对应的目录和对应的规则文件
package com.sid.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* 文件操作类,如果规则文件不存在就创建对应的目录和对应的规则文件
* */
public class RuleFileUtils {
private static final Logger logger = LoggerFactory.getLogger(RuleFileUtils.class);
/**
* 方法实现说明:若路径不存在就创建路径
*
* @param filePath:文件存储路径
*/
public static void mkdirIfNotExits(String filePath) throws IOException {
File file = new File(filePath);
if (!file.exists()) {
logger.info("创建Sentinel规则目录:{}", filePath);
file.mkdirs();
}
}
/**
* 方法实现说明:若文件不存在就创建路径
*
* @param ruleFileMap 规则存储文件
*/
public static void createFileIfNotExits(Map<String, String> ruleFileMap) throws IOException {
Set<String> ruleFilePathSet = ruleFileMap.keySet();
Iterator<String> ruleFilePathIter = ruleFilePathSet.iterator();
while (ruleFilePathIter.hasNext()) {
String ruleFilePathKey = ruleFilePathIter.next();
String ruleFilePath = PersistenceRuleConstant.rulesMap.get(ruleFilePathKey).toString();
File ruleFile = new File(ruleFilePath);
if (ruleFile.exists()) {
logger.info("创建Sentinel 规则文件:{}", ruleFile);
ruleFile.createNewFile();
}
}
}
}
规则的编码和解码操作类
package com.sid.config;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import java.util.List;
/**
* 规则的编码和解码操作类
* */
public class RuleListParserUtils {
/**
* 流控列表解析器
*/
public static final Converter<String, List<FlowRule>> flowRuleListParser = new Converter<String, List<FlowRule>>() {
@Override
public List<FlowRule> convert(String source) {
return JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
});
}
};
/**
* 流控列表 编码器
*/
public static final Converter<List<FlowRule>, String> flowRuleEnCoding = new Converter<List<FlowRule>, String>() {
@Override
public String convert(List<FlowRule> source) {
return JSON.toJSONString(source);
}
};
public static final Converter<String, List<DegradeRule>> degradeRuleListParser = source -> JSON.parseObject(source,
new TypeReference<List<DegradeRule>>() {
});
public static final Converter<List<DegradeRule>, String> degradeRuleEnCoding = new Converter<List<DegradeRule>, String>() {
@Override
public String convert(List<DegradeRule> source) {
return JSON.toJSONString(source);
}
};
public static final Converter<String, List<SystemRule>> systemRuleListParser = source -> JSON.parseObject(source,
new TypeReference<List<SystemRule>>() {
});
public static final Converter<List<SystemRule>, String> systemRuleEnCoding = new Converter<List<SystemRule>, String>() {
@Override
public String convert(List<SystemRule> source) {
return JSON.toJSONString(source);
}
};
public static final Converter<String, List<AuthorityRule>> authorityRuleListParser = source -> JSON
.parseObject(source, new TypeReference<List<AuthorityRule>>() {
});
public static final Converter<List<AuthorityRule>, String> authorityRuleEnCoding = new Converter<List<AuthorityRule>, String>() {
@Override
public String convert(List<AuthorityRule> source) {
return JSON.toJSONString(source);
}
};
public static final Converter<String, List<ParamFlowRule>> paramFlowRuleListParser = source -> JSON
.parseObject(source, new TypeReference<List<ParamFlowRule>>() {
});
// public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = new Converter<List<ParamFlowRule>, String>() {
// @Override
// public String convert(List<ParamFlowRule> source) {
// return JSON.toJSONString(source);
// }
// };
public static final Converter<List<ParamFlowRule>, String> paramFlowRuleEnCoding = source -> encodeJson(source);
private static <T> String encodeJson(T t) {
return JSON.toJSONString(t);
}
}
pull模式操作类
package com.sid.config;
import com.alibaba.csp.sentinel.command.handler.ModifyParamFlowRulesCommandHandler;
import com.alibaba.csp.sentinel.datasource.FileRefreshableDataSource;
import com.alibaba.csp.sentinel.datasource.FileWritableDataSource;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.datasource.WritableDataSource;
import com.alibaba.csp.sentinel.init.InitFunc;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRuleManager;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRule;
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRuleManager;
import com.alibaba.csp.sentinel.slots.system.SystemRule;
import com.alibaba.csp.sentinel.slots.system.SystemRuleManager;
import com.alibaba.csp.sentinel.transport.util.WritableDataSourceRegistry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.FileNotFoundException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
/**
* pull 模式的数据源(如本地文件、RDBMS 等)一般是可写入的。
* <p>
* 使用时需要在客户端注册数据源:
* 将对应的读数据源注册至对应的 RuleManager,将写数据源注册至 transport 的 WritableDataSourceRegistry 中。
*/
public class PullModeLocalFileDataSource implements InitFunc {
private static final Logger logger = LoggerFactory.getLogger(PullModeLocalFileDataSource.class);
private static final SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
@Override
public void init() throws Exception {
logger.info("time:{}读取配置", sdf.format(new Date()));
try {
// 创建文件存储目录(若路径不存在就创建路径)
RuleFileUtils.mkdirIfNotExits(PersistenceRuleConstant.storePath);
// 创建规则文件()
RuleFileUtils.createFileIfNotExits(PersistenceRuleConstant.rulesMap);
// 处理流控规则逻辑
dealFlowRules();
// 处理降级规则
dealDegradeRules();
// 处理系统规则
dealSystemRules();
// 热点参数规则
dealParamFlowRules();
// 授权规则
dealAuthRules();
} catch (Exception e) {
logger.error("错误原因:{}", e);
}
}
/**
* 方法实现说明:处理流控规则逻辑
*/
private void dealFlowRules() throws FileNotFoundException {
String ruleFilePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.FLOW_RULE_PATH).toString();
// 创建流控规则的可读数据源
ReadableDataSource<String, List<FlowRule>> flowRuleRDS = new FileRefreshableDataSource<>(ruleFilePath,
RuleListParserUtils.flowRuleListParser);
// 将可读数据源注册至FlowRuleManager 这样当规则文件发生变化时,就会更新规则到内存
FlowRuleManager.register2Property(flowRuleRDS.getProperty());
WritableDataSource<List<FlowRule>> flowRuleWDS = new FileWritableDataSource<List<FlowRule>>(ruleFilePath,
RuleListParserUtils.flowRuleEnCoding);
// 将可写数据源注册至 transport 模块的 WritableDataSourceRegistry 中.
// 这样收到控制台推送的规则时,Sentinel 会先更新到内存,然后将规则写入到文件中.
WritableDataSourceRegistry.registerFlowDataSource(flowRuleWDS);
}
// 处理降级规则
private void dealDegradeRules() throws FileNotFoundException {
String degradeRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.DEGRAGE_RULE_PATH).toString();
// 降级规则
ReadableDataSource<String, List<DegradeRule>> degradeRuleRDS = new FileRefreshableDataSource<>(degradeRulePath,
RuleListParserUtils.degradeRuleListParser);
DegradeRuleManager.register2Property(degradeRuleRDS.getProperty());
WritableDataSource<List<DegradeRule>> degradeRuleWDS = new FileWritableDataSource<>(degradeRulePath,
RuleListParserUtils.degradeRuleEnCoding);
WritableDataSourceRegistry.registerDegradeDataSource(degradeRuleWDS);
}
// 处理系统规则
private void dealSystemRules() throws FileNotFoundException {
String systemRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.SYSTEM_RULE_PATH).toString();
// 系统规则
ReadableDataSource<String, List<SystemRule>> systemRuleRDS = new FileRefreshableDataSource<>(systemRulePath,
RuleListParserUtils.systemRuleListParser);
SystemRuleManager.register2Property(systemRuleRDS.getProperty());
WritableDataSource<List<SystemRule>> systemRuleWDS = new FileWritableDataSource<>(systemRulePath,
RuleListParserUtils.systemRuleEnCoding);
WritableDataSourceRegistry.registerSystemDataSource(systemRuleWDS);
}
// 热点参数规则
private void dealParamFlowRules() throws FileNotFoundException {
String paramFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.HOT_PARAM_RULE).toString();
// 热点参数规则
ReadableDataSource<String, List<ParamFlowRule>> paramFlowRuleRDS = new FileRefreshableDataSource<>(
paramFlowRulePath, RuleListParserUtils.paramFlowRuleListParser);
ParamFlowRuleManager.register2Property(paramFlowRuleRDS.getProperty());
WritableDataSource<List<ParamFlowRule>> paramFlowRuleWDS = new FileWritableDataSource<>(paramFlowRulePath,
RuleListParserUtils.paramFlowRuleEnCoding);
ModifyParamFlowRulesCommandHandler.setWritableDataSource(paramFlowRuleWDS);
}
private void dealAuthRules() throws FileNotFoundException {
String authFlowRulePath = PersistenceRuleConstant.rulesMap.get(PersistenceRuleConstant.AUTH_RULE_PATH).toString();
//授权规则
ReadableDataSource<String, List<AuthorityRule>> authorityRuleRDS = new FileRefreshableDataSource<>(authFlowRulePath,
RuleListParserUtils.authorityRuleListParser);
AuthorityRuleManager.register2Property(authorityRuleRDS.getProperty());
WritableDataSource<List<AuthorityRule>> authorityRuleWDS = new FileWritableDataSource<>(authFlowRulePath,
RuleListParserUtils.authorityRuleEnCoding);
WritableDataSourceRegistry.registerAuthorityDataSource(authorityRuleWDS);
}
}
通过SPI扩展机制进行扩展,在微服务工程的resources目录下创建META-INF/services目录,并新建文件名为com.alibaba.csp.sentinel.init.InitFunc文件。内容是PullModeLocalFileDataSource类全路径类名
验证
在sentinel dashboard(http://localhost:8080/)中给app-order项目添加流控规则
app-order检测到流控规则的变化并产生flowRule.json文件
[{"clusterConfig":{"fallbackToLocalWhenFail":true,"sampleCount":10,"strategy":0,"thresholdType":0,"windowIntervalMs":1000},"clusterMode":false,"controlBehavior":0,"count":1.0,"grade":1,"limitApp":"default","maxQueueingTimeMs":500,"resource":"com.sid.rpc.service.service.OrderServiceApi:create(java.lang.String,java.lang.String,java.lang.Integer)","strategy":0,"warmUpPeriodSec":10}]
直接修改这个flowRule.json文件中的内容,也会在 sentinel dashboard(http://localhost:8080/)中看到变化
重启项目或者重启sentinel dashboard,能看到之前配置的流控信息都在
3.Push模式(持久化到nacos)
生产环境下一般更常用的是 push 模式的数据源。
对于 push 模式的数据源,如远程配置中心(ZooKeeper, Nacos, Apollo等等),推送的操作不应由 Sentinel 客户端进行,而应该经控制台统一进行管理,直接进行推送,数据源仅负责获取配置中心推送的配置并更新到本地。
换句话说就是实现Sentinel Dashboard与Nacos之间的相互通信:
1.Sentinel Dashboard界面配置流控规则---sentinel发布/推送--->Nacos生成配置文件并持久化;
2.通过Nacos配置文件修改流控规则---sentinel拉取--->Sentinel Dashboard界面显示最新的流控规则。
需要注意的是:
在Nacos控制台上修改流控制,虽然可以同步到Sentinel Dashboard,但是Nacos此时应该作为一个流控规则的持久化平台,所以正常操作过程应该是开发者在Sentinel Dashboard上修改流控规则后同步到Nacos,遗憾的是目前Sentinel Dashboard不支持该功能。
试想下,如果公司没有统一在Sentinel Dashboard或Nacos中二选一进行配置,而是一会在Sentinel Dashboard配置,一会在Nacos配置。那么就会出现很严重的问题(流控规则达不到预期,配置数据不一致),所以推荐使用Sentinel Dashboard统一界面进行配置管理流控规则
正因为Sentinel Dashboard当前版本(截至目前为止是1.8.1-SNAPSHOT)暂不支持,但是可以通过改造部分源码实现此功能
修改sentinel-dashboard项目源码
先下载sentinel源码:https://github.com/alibaba/Sentinel
切换到自己对应的分支(1.8.1)
控制台改造主要是为规则实现
- DynamicRuleProvider:从Nacos上读取配置
- DynamicRulePublisher:将规则推送到Nacos上
pom中
<!-- for Nacos rule publisher sample -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<!--注释掉原文件中的scope,让其不仅在test的时候生效-->
<!--<scope>test</scope>-->
</dependency>
复制sentinel-dashboard项目下test下的nacos包
src/test/java/com/alibaba/csp/sentinel/dashboard/rule/nacos到 src/main/java/com/alibaba/csp/sentinel/dashboard/rule下
修改controller中的默认provider & publisher
com.alibaba.csp.sentinel.dashboard.controller.v2.FlowControllerV2中
@Autowired
// @Qualifier("flowRuleDefaultProvider")
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
// @Qualifier("flowRuleDefaultPublisher")
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
打开 /Sentinel-1.8.1/sentinel-dashboard/src/main/webapp/resources/app/scripts/directives/sidebar/sidebar.html文件,修改代码
<li ui-sref-active="active" ng-if="!entry.isGateway">
<a ui-sref="dashboard.flowV1({app: entry.app})">
<i class="glyphicon glyphicon-filter"></i> 流控规则</a>
</li>
把V1去掉,就是这个flowV1改成flow
复制过来的这几个类要修改,且新增一个NacosPropertiesConfiguration类
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 dataId;
private String groupId = "SENTINEL_GROUP"; // 默认分组
private String namespace;
//省略getter setter
}
NacosConfig要修改为
package com.alibaba.csp.sentinel.dashboard.rule.nacos;
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<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
return s -> JSON.parseArray(s, FlowRuleEntity.class);
}
@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());
return ConfigFactory.createConfigService(properties);
// return ConfigFactory.createConfigService("localhost");
}
}
修改FlowRuleNacosPublisher
@Service("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));
}
}
修改类FlowRuleNacosProvider
@Service("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);
}
}
修改配置文件application.properties在末尾加入
# nacos config server
sentinel.nacos.serverAddr=localhost:8848
sentinel.nacos.namespace=
sentinel.nacos.group-id=SENTINEL_GROUP
重新打包sentinel项目(记得是把整个sentinel项目重新打包,不是只打包dashboard,怕有东西没打进去)
mvn clean package -DskipTests
启动这个打出来的包
业务系统代码修改
引入依赖
<!-- Sentinel支持采用 Nacos 作为规则配置数据源,引入该适配依赖-->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<version>1.7.2</version>
</dependency>
application.yml添加配置
datasource:
#自定义的数据源名称,可以多个,必须唯一,可以理解为通过该数据源指定
#读取哪个位置的哪个文件中的数据,此处表示读取 Nacos 配置中心上的
#名为 cloudalibaba-sentinel-service 类型为 json 文件中的数据
#前提是指定的 Nacos 配置中心中要有该文件,该文件中保存的是,Sentinel
#对当前服务或服务中的接口设置的流控,熔断降级等相关的数据
ds1:
nacos:
server-addr: localhost:8848 #存放数据的数据源地址,通过 Nacos 保存相关数据
dataId: app-account-flow-rules #读取 Ncaos 配置中心上文件的名称
groupId: SENTINEL_GROUP #读取 Nacos 配置中心哪个分组id
data-type: json #读取 Nacos 配置中心上的什么类型的文件
rule-type: flow #读取的规则类型
在nacos中创建sentinel的规则配置文件
[
{
"resource": "account-debit",//对应 Sentinel 中的资源名称(接口请求路径,或指定的资源名称)
"limitApp": "default",//对应 Sentinel 中的来源应用(在Stinel中一般使用默认的)
"grade": 1, //对应 Sentinel 设置的阈值类型,0 表示线程数,1 表示QPS
"count": 10,//对应 Sentinel 设置的单机阈值
"strategy": 0,//对应 Sentinel 设置的流程模式,0直接,1关联,2链路
"controlBehavior": 0,//对应 Sentinel 流程效果,0快速失败,1WarmUp,2排队等待
"clusterMode": false //对应 Sentinel 设置的是否集群
}
]
在项目启动后访问该服务中的任意一个接口时,会自动通过配置的 Sentinel 数据源读取 Nacos 上的指定的文件,加载配置内容,获取到针对该服务的流控,熔断,降级等相关数据
(如果启动服务不妨问服务中的任何借口,默认是不会主动去读取数据的,Sentinel 流控页显示为空)
可以尝试在sentinel改变阈值,在nacos中能看到。(失败、好吧,是我理解错了)
在nacos中改变阈值,在sentinel中能看到。(成功)
那在sentinel中改变了阈值,在nacos中看不到,问题出来哪里呢,经过尝试,发现本来我nacos没有用mysql,如果我把我nacos本身的数据存储到mysql中,那sentinel修改后会同步到nacos上