# Sentinel **Repository Path**: moxi159753/Sentinel ## Basic Information - **Project Name**: Sentinel - **Description**: No description available - **Primary Language**: Unknown - **License**: Apache-2.0 - **Default Branch**: dashboard-nacos - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 6 - **Created**: 2021-12-03 - **Last Updated**: 2021-12-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README 官网 git: [Sentinel](https://github.com/alibaba/Sentinel) 改造后源码:[dashboard-nacos分支](https://gitee.com/it00021hot/Sentinel.git) sentinel版本:1.8.1 改造的规则有:授权规则、降级规则、流控规则、热点规则、系统规则 ## 改造过程 #### 修改pom.xml - 下载源码,idea打开。 - 找到sentinel-dashboard这个项目 - 在该项目下的pom.xml文件中找到: ```xml com.alibaba.csp sentinel-datasource-nacos ``` #### 修改application.properties配置文件 **添加如下配置:** ```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 需要微服务客户端的一致 ```java 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 --- 1. 在publisher包下编写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> { @Autowired private ConfigService configService; @Autowired private FlowRuleConvert converter; @Override public void publish(String app, List 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"); } } } ``` 2. 在convert包下编写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, String> { @Override public String convert(List flowRuleEntities) { if(flowRuleEntities==null){ return null; } List 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); } } ``` 3. 在provider包下编写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> { @Autowired private ConfigService configService; @Autowired private Converter> converter; @Override public List 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); } } ``` 4. 在nacos包下编写NacosConfig ```java 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> flowRuleEntityDecoder() { return s -> JSON.parseArray(s, FlowRuleEntity.class); } @Bean public ParamFlowRuleConvert paramFlowRuleEntityEncoder() { return new ParamFlowRuleConvert(); } @Bean public Converter> 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> degradeRuleEntityDecoder() { return s -> JSON.parseArray(s, DegradeRuleEntity.class); } @Bean public AuthorityRuleConvert authorityRuleConvert() { return new AuthorityRuleConvert(); } @Bean public Converter> 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> 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; } } ``` 5. 修改FlowControllerV1 ```java /* 添加rulePublisher和ruleProvider */ @Autowired @Qualifier("flowRuleNacosProvider") private DynamicRuleProvider> ruleProvider; @Autowired @Qualifier("flowRuleNacosPublisher") private DynamicRulePublisher> rulePublisher; ``` ```java /** * 改造publishRules方法,调用该方法的代码请修改参数和返回值 * @param app 客户端名称 * @throws Exception */ private void publishRules(/*@NonNull*/ String app) throws Exception { List rules = repository.findAllByApp(app); if(nacosConfig.isEnable()){ rulePublisher.publish(app,rules); } } ``` ```java /** * 修改查询规则列表接口 * @param app 应用名称 * @param ip 规则提供者ip * @param port 端口 * @return */ @GetMapping("/rules") @AuthAction(PrivilegeType.READ_RULE) public Result> 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 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分支](https://gitee.com/it00021hot/Sentinel.git) 6. 客户端配置 ```yaml 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 ```