注:目前发现sentinel修改nacos还是无效,等后续修改
之前写了关于nacos的部署,接着上次的文章写,我们开始部署限流组件Sentinel
如果没有部署nacos的同学可以参照这个进行部署记一次服务器完整安装至上线的大部分流程(六、nacos部署)
这次的部署涉及到两部分,及额外部分说明
文章目录
目录
前言
Sentinel在实际使用的最多场景为高并发情况下保护服务不会因为大量请求而击垮服务,例如红包,订单体系的系统,这时候需要有个组件帮助我们将大量的请求挡在外面,这时候需要将大量的请求等待或直接拒绝;还有种场景是在平常某个服务很少被请求,但某个时间点请求数到达比平常突增几倍的时候也会冲垮服务,这时候需要进行对服务预热;还有一种场景,当A服务调用B服务的时候,B服务挂了,那么A服务一定会引起雪崩,整个服务体系都会崩塌,依赖A服务的接口可能也会报错,这时候就需要进行熔断
一、Sentinel是什么?
随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。
Sentinel 具有以下特征:
- 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
- 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
- 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Apache Dubbo、gRPC、Quarkus 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。同时 Sentinel 提供 Java/Go/C++ 等多语言的原生实现。
- 完善的 SPI 扩展机制:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。
二、使用环境
首先我们先确认自己的环境来安装对应的版本依赖
三、可视化安装
四、服务端设置
五、额外操作,双向推拉
光是nacos的配置到sentinel肯定不符合线上设置,所以我们需要对sentinel的源码进行修改打包
1.下载源码
上面我们用的版本是V1.8.0,所以我们也下载对应的源码版本链接如下https://github.com/alibaba/Sentinel/releases/tag/v1.8.0
下载后我们用idea打开,开始修改
2.修改 POM
由于我们是nacos进行持久化储存的,官方默认是导入了的,但仅限于测试,所以我们需要注释调使用环境
注释scope即可
3.修改配置文件
sentinel.nacos.serverAddr nacos的地址
sentinel.nacos.namespace nacos的命名空间
sentinel.nacos.group-id nacos该服务的分组id
4.修改后端代码
注:导包注意 Converter的包是sentinel的
-
首先将该目录迁移过去
第一步就完成了
-
修改配置文件
修改第一个文件 NacosPropertiesConfig
建议复制
@Configuration
public class NacosConfig {
/**
* nacos注册地址
*/
@Value("${sentinel.nacos.serverAddr}")
private String address;
/**
* nacos命名空间
*/
@Value("${sentinel.nacos.namespace}")
private String namespace;
@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 Converter<List<DegradeRuleEntity>, String> degradeRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
return s -> JSON.parseArray(s, DegradeRuleEntity.class);
}
@Bean
public Converter<List<ParamFlowRuleEntity>, String> paramsRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<ParamFlowRuleEntity>> paramsRuleEntityDecoder() {
return s -> JSON.parseArray(s, ParamFlowRuleEntity.class);
}
@Bean
public Converter<List<SystemRuleEntity>, String> systemRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean
public Converter<String, List<SystemRuleEntity>> systemRuleEntityDecoder() {
return s -> JSON.parseArray(s, SystemRuleEntity.class);
}
@Bean
public Converter<List<AuthorityRuleEntity>, String> authRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean Converter<String,List<AuthorityRuleEntity>> authRuleEntityDecoder(){
return s-> JSON.parseArray(s, AuthorityRuleEntity.class);
}
@Bean
public Converter<List<GatewayFlowRuleEntity>, String> gatewayFlowRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean Converter<String,List<GatewayFlowRuleEntity>> gatewayFlowRuleEntityDecoder(){
return s-> JSON.parseArray(s, GatewayFlowRuleEntity.class);
}
@Bean
public Converter<List<ApiDefinitionEntity>, String> gatewayApiRuleEntityEncoder() {
return JSON::toJSONString;
}
@Bean Converter<String,List<ApiDefinitionEntity>> gatewayApiRuleEntityDecoder(){
return s-> JSON.parseArray(s, ApiDefinitionEntity.class);
}
@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);
}
}
写入两个配置进去,一个是nacos地址,一个是命名空间
-
修改NacosConfigUtil
添加两行
public static final String GATEWAY_FLOW_DATA_ID_POSTFIX = "-gateway-flow";
public static final String GATEWAY_API_DATA_ID_POSTFIX = "-gateway-api";
公共类修改完了,接着需要创建对应的nacos相关类
在这里创建下面两个类
@Component("authRuleNacosProvider")
public class AuthorityRuleNacosProvider implements DynamicRuleProvider<List<AuthorityRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthorityRuleNacosProvider.class);
@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.AUTH_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
LOGGER.info("get auth rule from nacos, rules : {}", rules);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
@Component("authRuleNacosPublisher")
public class AuthorityRuleNacosPublisher implements DynamicRulePublisher<List<AuthorityRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(AuthorityRuleNacosPublisher.class);
@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;
}
String convertedRule = converter.convert(rules);
LOGGER.info("sentinel dashboard publisher auth rules : {}", convertedRule);
configService.publishConfig(app + NacosConfigUtil.AUTH_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, convertedRule);
}
}
完成后的样子
-
创建与nacos降级规则
@Component("degradeRuleNacosProvider")
public class DegradeRuleNacosProvider implements DynamicRuleProvider<List<DegradeRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(DegradeRuleNacosProvider.class);
@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);
LOGGER.info("get degrade rules from nacos, rules: {}", rules);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
@Component("degradeRuleNacosPublisher")
public class DegradeRuleNacosPublisher implements DynamicRulePublisher<List<DegradeRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(DegradeRuleNacosPublisher.class);
@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;
}
String convertedRule = converter.convert(rules);
LOGGER.info("sentinel dashboard publish degrade rules: {}", convertedRule);
configService.publishConfig(app + NacosConfigUtil.DEGRADE_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, convertedRule);
}
}
-
创建网关流控规则
@Component("gatewayApiRuleNacosProvider")
public class GatewayApiRuleNacosProvider implements DynamicRuleProvider<List<ApiDefinitionEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(GatewayApiRuleNacosProvider.class);
@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);
LOGGER.info("get gateway api rules from nacos, rules: {}", rules);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
@Component("gatewayApiRuleNacosPublisher")
public class GatewayApiRuleNacosPublisher implements DynamicRulePublisher<List<ApiDefinitionEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(GatewayApiRuleNacosPublisher.class);
@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;
}
String convertedRule = converter.convert(rules);
LOGGER.info("sentinel dashboard publish gateway api rules: {}", convertedRule);
configService.publishConfig(app + NacosConfigUtil.GATEWAY_API_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, convertedRule);
}
}
@Component("gatewayFlowRuleNacosProvider")
public class GatewayFlowRuleNacosProvider implements DynamicRuleProvider<List<GatewayFlowRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(GatewayFlowRuleNacosProvider.class);
@Autowired
private ConfigService configService;
@Autowired
private Converter<String, List<GatewayFlowRuleEntity>> converter;
@Override
public List<GatewayFlowRuleEntity> getRules(String appName) throws Exception {
String rules = configService.getConfig(appName + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
LOGGER.info("get gateway flow rules from nacos, rules: {}", rules);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
@Component("gatewayFlowRuleNacosPublisher")
public class GatewayFlowRuleNacosPublisher implements DynamicRulePublisher<List<GatewayFlowRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(GatewayFlowRuleNacosPublisher.class);
@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;
}
String convertedRule = converter.convert(rules);
LOGGER.info("sentinel dashboard publish gateway flow rules: {}", convertedRule);
configService.publishConfig(app + NacosConfigUtil.GATEWAY_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, convertedRule);
}
}
-
创建与nacos热点规则
@Component("paramRuleNacosProvider")
public class ParamRuleNacosProvider implements DynamicRuleProvider<List<ParamFlowRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(ParamRuleNacosProvider.class);
@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);
LOGGER.info("get param rules from nacos, rules: {}", rules);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
@Component("paramRuleNacosPublisher")
public class ParamRuleNacosPublisher implements DynamicRulePublisher<List<ParamFlowRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(ParamRuleNacosPublisher.class);
@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;
}
String convertedRule = converter.convert(rules);
LOGGER.info("sentinel dashboard publish param rules: {}", convertedRule);
configService.publishConfig(app + NacosConfigUtil.PARAM_FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, convertedRule);
}
}
-
创建与nacos系统规则
@Component("systemRuleNacosProvider")
public class SystemRuleNacosProvider implements DynamicRuleProvider<List<SystemRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemRuleNacosProvider.class);
@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.SYS_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, 3000);
LOGGER.info("get system rules from nacos, rules: {}", rules);
if (StringUtil.isEmpty(rules)) {
return new ArrayList<>();
}
return converter.convert(rules);
}
}
@Component("systemRuleNacosPublisher")
public class SystemRuleNacosPublisher implements DynamicRulePublisher<List<SystemRuleEntity>> {
private static final Logger LOGGER = LoggerFactory.getLogger(SystemRuleNacosPublisher.class);
@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;
}
String convertedRule = converter.convert(rules);
LOGGER.info("sentinel dashboard publisher system rule : {}", convertedRule);
configService.publishConfig(app + NacosConfigUtil.SYS_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, convertedRule);
}
}
-
修改 Controller
修改AuthorityRuleController
添加两个依赖注入
@Autowired
@Qualifier("authRuleNacosProvider")
private DynamicRuleProvider<List<AuthorityRuleEntity>> ruleProvider;
@Autowired
@Qualifier("authRuleNacosPublisher")
private DynamicRulePublisher<List<AuthorityRuleEntity>> rulePublisher;
修改这一块代码
// List<AuthorityRuleEntity> rules = sentinelApiClient.fetchAuthorityRulesOfMachine(app, ip, port);
List<AuthorityRuleEntity> rules = ruleProvider.getRules(app);
// return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);
try {
rulePublisher.publish(app, rules);
return true;
} catch (Exception e) {
return false;
}
修改DegradeController
导入两个依赖
@Autowired
@Qualifier("degradeRuleNacosProvider")
private DynamicRuleProvider<List<DegradeRuleEntity>> ruleProvider;
@Autowired
@Qualifier("degradeRuleNacosPublisher")
private DynamicRulePublisher<List<DegradeRuleEntity>> rulePublisher;
// List<DegradeRuleEntity> rules = sentinelApiClient.fetchDegradeRuleOfMachine(app, ip, port);
List<DegradeRuleEntity> rules = ruleProvider.getRules(app);
// return sentinelApiClient.setDegradeRuleOfMachine(app, ip, port, rules);
try{
rulePublisher.publish(app, rules);
return true;
}catch (Exception e){
return false;
}
修改FlowControllerV2
注入两个依赖,注释前面的依赖
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
修改GatewayApiController
@Autowired
@Qualifier("gatewayApiRuleNacosProvider")
private DynamicRuleProvider<List<ApiDefinitionEntity>> provider;
@Autowired
@Qualifier("gatewayApiRuleNacosPublisher")
private DynamicRulePublisher<List<ApiDefinitionEntity>> publisher;
// List<ApiDefinitionEntity> apis = sentinelApiClient.fetchApis(app, ip, port).get();
List<ApiDefinitionEntity> apis = provider.getRules(app);
// return sentinelApiClient.modifyApis(app, ip, port, apis);
try {
publisher.publish(app, apis);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
修改 GatewayFlowRuleController
@Autowired
@Qualifier("gatewayFlowRuleNacosProvider")
private DynamicRuleProvider<List<GatewayFlowRuleEntity>> provider;
@Autowired
@Qualifier("gatewayFlowRuleNacosPublisher")
private DynamicRulePublisher<List<GatewayFlowRuleEntity>> publisher;
// List<GatewayFlowRuleEntity> rules = sentinelApiClient.fetchGatewayFlowRules(app, ip, port).get();
List<GatewayFlowRuleEntity> rules = provider.getRules(app);
// return sentinelApiClient.modifyGatewayFlowRules(app, ip, port, rules);
try {
publisher.publish(app, rules);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
修改ParamFlowRuleController
@Autowired
@Qualifier("paramRuleNacosProvider")
private DynamicRuleProvider<List<ParamFlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("paramRuleNacosPublisher")
private DynamicRulePublisher<List<ParamFlowRuleEntity>> rulePublisher;
List<ParamFlowRuleEntity> rules = ruleProvider.getRules(app);
repository.saveAll(rules);
return Result.ofSuccess(rules);
private void publishRules(String app) throws Exception {
List<ParamFlowRuleEntity> rules = repository.findAllByApp(app);
rulePublisher.publish(app, rules);
}
// publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get();
publishRules(entity.getApp());
// publishRules(entity.getApp(), entity.getIp(), entity.getPort()).get();
publishRules(entity.getApp());
// publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort()).get();
publishRules(oldEntity.getApp());
修改SystemController
@Autowired
@Qualifier("systemRuleNacosProvider")
private DynamicRuleProvider<List<SystemRuleEntity>> ruleProvider;
@Autowired
@Qualifier("systemRuleNacosPublisher")
private DynamicRulePublisher<List<SystemRuleEntity>> rulePublisher;
// List<SystemRuleEntity> rules = sentinelApiClient.fetchSystemRuleOfMachine(app, ip, port);
List<SystemRuleEntity> rules = ruleProvider.getRules(app);
// return sentinelApiClient.setSystemRuleOfMachine(app, ip, port, rules);
try {
rulePublisher.publish(app, rules);
return true;
} catch (Exception e) {
return false;
}
5.修改前端代码
修改 sidebar.html
修改flow_service_v1.js
修改identity.js
修改flow_v2.html
注释掉
到这改造完毕
6.编译打包测试
-
编译前端
到resources下
直接目录上cmd然后npm打包
npm install
npm run build
-
编译打包后端
mvn clean package -Dmaven.test.skip=true
总结