sentinel-nacos推模式改造
官网 git: Sentinel改造后源码:dashboard-nacos分支sentinel版本:1.8.1改造的规则有:授权规则、降级规则、流控规则、热点规则、系统规则改造过程修改pom.xml下载源码,idea打开。找到sentinel-dashboard这个项目在该项目下的pom.xml文件中找到:<!-- 将<scope>test</scope>注释掉。 -
·
官网 git: Sentinel
改造后源码:dashboard-nacos分支
sentinel版本:1.8.1
改造的规则有:授权规则、降级规则、流控规则、热点规则、系统规则
改造过程
修改pom.xml
- 下载源码,idea打开。
- 找到sentinel-dashboard这个项目
- 在该项目下的pom.xml文件中找到:
<!-- 将<scope>test</scope>注释掉。 -->
<dependency>
<groupId>com.alibaba.csp</groupId>
<artifactId>sentinel-datasource-nacos</artifactId>
<!-- <scope>test</scope>-->
</dependency>
修改application.properties配置文件
添加如下配置:
# nacos settings
sentinel.datasource.nacos.enable=true
sentinel.datasource.nacos.server-addr=10.168.1.99:8848
sentinel.datasource.nacos.namespace=dev
修改代码,以流控规则为例
在java->com.alibaba.csp.sentinel.dashboard下添加nacos包
添加NacosConfigUtil.java
注意 GROUP_ID 、xx_DATA_ID_POSTFIX 需要微服务客户端的一致
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 PARAM_FLOW_DATA_ID_POSTFIX = "-param-rules";
public static final String DEGRADE_DATA_ID_POSTFIX = "-degrade-rules";
public static final String AUTHORITY_DATA_ID_POSTFIX = "-authority-rules";
public static final String SYSTEM_DATA_ID_POSTFIX = "-system-rules";
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() {}
}
在nacos新建三个包
- convert
- provider
- publisher
- 在publisher包下编写FlowRuleNacosPublisher 规则发布
FlowRuleNacosPublisher.java
/*
* Copyright 1999-2018 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.csp.sentinel.dashboard.nacos.publisher;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.dashboard.nacos.convert.FlowRuleConvert;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.csp.sentinel.util.AssertUtil;
import com.alibaba.nacos.api.config.ConfigService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;
/**
* @author Eric Zhao
* @since 1.4.0
*/
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {
@Autowired
private ConfigService configService;
@Autowired
private FlowRuleConvert converter;
@Override
public void publish(String app, List<FlowRuleEntity> rules) throws Exception {
AssertUtil.notEmpty(app, "app name cannot be empty");
if (rules == null) {
return;
}
boolean success = configService.publishConfig(app + NacosConfigUtil.FLOW_DATA_ID_POSTFIX,
NacosConfigUtil.GROUP_ID, converter.convert(rules));
if(!success){
throw new RuntimeException("publish to nacos fail");
}
}
}
- 在convert包下编写FlowRuleConvert转换类
FlowRuleConvert.java
package com.alibaba.csp.sentinel.dashboard.nacos.convert;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.fastjson.JSON;
import java.util.ArrayList;
import java.util.List;
/**
* @author T6001270
* @since 2020/9/30 4:18
*/
public class FlowRuleConvert implements Converter<List<FlowRuleEntity>, String> {
@Override
public String convert(List<FlowRuleEntity> flowRuleEntities) {
if(flowRuleEntities==null){
return null;
}
List<FlowRule> flowRules = new ArrayList<>();
for (FlowRuleEntity entity : flowRuleEntities) {
FlowRule rule = new FlowRule();
rule.setLimitApp(entity.getLimitApp());
rule.setResource(entity.getResource());
if(entity.getGmtCreate()!=null){
rule.setGrade(entity.getGrade());
}
if(entity.getCount()!=null){
rule.setCount(entity.getCount());
}
if(entity.getStrategy()!=null){
rule.setStrategy(entity.getStrategy());
}
rule.setRefResource(entity.getRefResource());
if(entity.getControlBehavior()!=null){
rule.setControlBehavior(entity.getControlBehavior());
}
if(entity.getWarmUpPeriodSec()!=null){
rule.setWarmUpPeriodSec(entity.getWarmUpPeriodSec());
}
if(entity.getMaxQueueingTimeMs()!=null){
rule.setMaxQueueingTimeMs(entity.getMaxQueueingTimeMs());
}
rule.setClusterMode(entity.isClusterMode());
rule.setClusterConfig(entity.getClusterConfig());
flowRules.add(rule);
}
return JSON.toJSONString(flowRules,true);
}
}
- 在provider包下编写FlowRuleNacosProvider获取规则
FlowRuleNacosProvider.java
package com.alibaba.csp.sentinel.dashboard.nacos.provider;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.nacos.NacosConfigUtil;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
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 T6001270
* @since 2020/9/30 4:18
*/
@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);
}
}
- 在nacos包下编写NacosConfig
package com.alibaba.csp.sentinel.dashboard.nacos;
import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.*;
import com.alibaba.csp.sentinel.dashboard.nacos.convert.*;
import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.slots.block.authority.AuthorityRule;
import com.alibaba.csp.sentinel.slots.block.flow.param.ParamFlowRule;
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.Objects;
import java.util.Properties;
import java.util.stream.Collectors;
/**
* @author T6001270
* @since 2020/9/30 4:18
*/
@Configuration
public class NacosConfig {
@Value("${sentinel.datasource.nacos.server-addr:localhost:8848}")
private String serverAddr;
@Value("${sentinel.datasource.nacos.enable:false}")
private boolean enable;
@Value("${sentinel.datasource.nacos.namespace:public}")
private String namespace;
@Bean
public FlowRuleConvert flowRuleEntityEncoder() {
return new FlowRuleConvert();
}
@Bean
public Converter<String, List<FlowRuleEntity>> flowRuleEntityDecoder() {
return s -> JSON.parseArray(s, FlowRuleEntity.class);
}
@Bean
public ParamFlowRuleConvert paramFlowRuleEntityEncoder() {
return new ParamFlowRuleConvert();
}
@Bean
public Converter<String, List<ParamFlowRuleEntity>> paramFlowRuleEntityDecoder() {
return s -> JSON.parseArray(s, ParamFlowRule.class).stream().filter(Objects::nonNull).map(ParamFlowRuleEntity::new).collect(Collectors.toList());
}
@Bean
public DegradeRuleConvert degradeRuleEntityEncoder() {
return new DegradeRuleConvert();
}
@Bean
public Converter<String, List<DegradeRuleEntity>> degradeRuleEntityDecoder() {
return s -> JSON.parseArray(s, DegradeRuleEntity.class);
}
@Bean
public AuthorityRuleConvert authorityRuleConvert() {
return new AuthorityRuleConvert();
}
@Bean
public Converter<String, List<AuthorityRuleEntity>> authorityRuleEntityDecoder() {
return s -> JSON.parseArray(s, AuthorityRule.class).stream().filter(Objects::nonNull).map(AuthorityRuleEntity::new).collect(Collectors.toList());
}
@Bean
public SystemRuleConvert systemRuleConvert() {
return new SystemRuleConvert();
}
@Bean
public Converter<String, List<SystemRuleEntity>> systemRuleEntityDecoder() {
return s -> JSON.parseArray(s, SystemRuleEntity.class);
}
@Bean
public ConfigService nacosConfigService() throws Exception {
Properties properties = new Properties();
properties.put("serverAddr", serverAddr);
properties.put(PropertyKeyConst.NAMESPACE, namespace);
return ConfigFactory.createConfigService(properties);
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
- 修改FlowControllerV1
/* 添加rulePublisher和ruleProvider */
@Autowired
@Qualifier("flowRuleNacosProvider")
private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;
@Autowired
@Qualifier("flowRuleNacosPublisher")
private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;
/**
* 改造publishRules方法,调用该方法的代码请修改参数和返回值
* @param app 客户端名称
* @throws Exception
*/
private void publishRules(/*@NonNull*/ String app) throws Exception {
List<FlowRuleEntity> rules = repository.findAllByApp(app);
if(nacosConfig.isEnable()){
rulePublisher.publish(app,rules);
}
}
/**
* 修改查询规则列表接口
* @param app 应用名称
* @param ip 规则提供者ip
* @param port 端口
* @return
*/
@GetMapping("/rules")
@AuthAction(PrivilegeType.READ_RULE)
public Result<List<FlowRuleEntity>> apiQueryMachineRules(@RequestParam String app,
@RequestParam String ip,
@RequestParam Integer port) {
if (StringUtil.isEmpty(app)) {
return Result.ofFail(-1, "app can't be null or empty");
}
if (StringUtil.isEmpty(ip)) {
return Result.ofFail(-1, "ip can't be null or empty");
}
if (port == null) {
return Result.ofFail(-1, "port can't be null");
}
try {
/*修改从提供者获取规则方式 */
List<FlowRuleEntity> rules = ruleProvider.getRules(app);
if (rules != null && !rules.isEmpty()) {
for (FlowRuleEntity entity : rules) {
entity.setApp(app);
entity.setPort(port);
entity.setIp(ip);
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);
}
}
其他规则修改步骤类似,具体代码参考dashboard-nacos分支
- 客户端配置
spring:
cloud:
# 配置Sentinel流控
sentinel:
transport:
#配置Sentinel dashboard地址
dashboard: 127.0.0.1:8080
#默认8719端口,如果被占用会向上扫描。
port: 8719
datasource:
# 分组与命名空间和服务端保持一致
flow:
nacos:
server-addr: 10.168.1.99:8848
dataId: ${spring.application.name}-flow-rules # 都是在 sentinel源码持久化改造中的规则名称
groupId: SENTINEL_GROUP
namespace: dev
rule-type: flow
degrade:
nacos:
server-addr: 10.168.1.99:8848
dataId: ${spring.application.name}-degrade-rules # 都是在 sentinel源码持久化改造中的规则名称
groupId: SENTINEL_GROUP
namespace: dev
rule-type: degrade
system:
nacos:
server-addr: 10.168.1.99:8848
dataId: ${spring.application.name}-system-rules # 都是在 sentinel源码持久化改造中的规则名称
groupId: SENTINEL_GROUP
namespace: dev
rule-type: system
authority:
nacos:
server-addr: 10.168.1.99:8848
dataId: ${spring.application.name}-authority-rules # 都是在 sentinel源码持久化改造中的规则名称
groupId: SENTINEL_GROUP
namespace: dev
rule-type: authority
param-flow:
nacos:
server-addr: 10.168.1.99:8848
dataId: ${spring.application.name}-param-flow-rules # 都是在 sentinel源码持久化改造中的规则名称
groupId: SENTINEL_GROUP
namespace: dev
rule-type: param-flow
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
已为社区贡献1条内容
所有评论(0)