文章目录

  • 一、前言
  • 二、快速体验
    • 1、部署sentinel
    • 2、SpringCloud中规则持久化到nacos
    • 3、sentinel控制台操作测试
  • 三、sentinel-dashboard源码修改
    • 1、`pom.xml`中添加依赖
    • 2、`application.properties`中添加nacos配置
    • 3、nacos配置
      • 新增NacosConfig
      • 新增NacosConfigUtil
    • 4、举例持久化流控规则
      • 新增FlowRuleNacosProvider
      • 新增FlowRuleNacosPublisher
      • 修改FlowControllerV1
  • 四、本文案例源码

一、前言

在生产环境中使用 Sentinel
参考 https://blog.csdn.net/liuerchong/article/details/123718092

下面使用Push模式:配置中心控制台/Sentinel 控制台 → 配置中心 → Sentinel 数据源 → Sentinel

二、快速体验

1、部署sentinel

小编已经基于Sentinel 1.8.4版本构建好一个docker镜像,修改下相应nacos配置信息即可运行体验一下

# 环境准备
git clone https://gitee.com/zhengqingya/docker-compose.git
cd docker-compose/Liunx
# 运行
# docker-compose -f docker-compose-sentinel-nacos.yml -p sentinel up -d

2、SpringCloud中规则持久化到nacos

添加依赖

<!-- Sentinel规则持久化至Nacos -->
<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-nacos</artifactId>
</dependency>

添加配置

spring:application:name: demo # 应用名称cloud:sentinel:enabled: true # 自动化配置是否生效eager: true   # 禁用控制台懒加载transport:dashboard: www.zhengqingya.com:8858 # 控制台地址client-ip: ${spring.cloud.client.ip-address} # 获取本机IP地址port: 18719 # 启动该服务,会在应用程序的相应服务器上启动HTTP Server,并且该服务器将与Sentinel dashboard进行交互# ============== ↓↓↓↓↓↓ 增加规则持久化配置到nacos ↓↓↓↓↓↓ ==============datasource:# 流控规则flow:nacos:server-addr: ${spring.cloud.nacos.config.server-addr}username: ${spring.cloud.nacos.config.username}password: ${spring.cloud.nacos.config.password}namespace: ${spring.cloud.nacos.config.namespace}group-id: sentinel-groupdata-id: ${spring.application.name}-sentinel-flow-rules# 规则类型:flow、degrade、param-flow、system、authorityrule-type: flow# 熔断降级degrade:nacos:server-addr: ${spring.cloud.nacos.config.server-addr}username: ${spring.cloud.nacos.config.username}password: ${spring.cloud.nacos.config.password}namespace: ${spring.cloud.nacos.config.namespace}group-id: sentinel-groupdata-id: ${spring.application.name}-sentinel-degrade-rulesrule-type: degrade# 热点规则param-flow:nacos:server-addr: ${spring.cloud.nacos.config.server-addr}username: ${spring.cloud.nacos.config.username}password: ${spring.cloud.nacos.config.password}namespace: ${spring.cloud.nacos.config.namespace}group-id: sentinel-groupdata-id: ${spring.application.name}-sentinel-param-flow-rulesrule-type: param-flow# 系统规则system:nacos:server-addr: ${spring.cloud.nacos.config.server-addr}username: ${spring.cloud.nacos.config.username}password: ${spring.cloud.nacos.config.password}namespace: ${spring.cloud.nacos.config.namespace}group-id: sentinel-groupdata-id: ${spring.application.name}-sentinel-system-rulesrule-type: system# 授权规则authority:nacos:server-addr: ${spring.cloud.nacos.config.server-addr}username: ${spring.cloud.nacos.config.username}password: ${spring.cloud.nacos.config.password}namespace: ${spring.cloud.nacos.config.namespace}group-id: sentinel-groupdata-id: ${spring.application.name}-sentinel-authority-rulesrule-type: authority

3、sentinel控制台操作测试

ex: 在sentinel控制台中添加流控规则会自动在nacos中创建相应配置文件xxx-sentinel-flow-rulesxxx-sentinel-flow-rules-sentinel-dashboard,用于规则持久化存储数据,sentinel重启或我们的应用app重启,配置都会一直在!

三、sentinel-dashboard源码修改

拉取源码 https://github.com/alibaba/Sentinel,进入sentinel-dashboard模块

1、pom.xml中添加依赖

<!--添加Nacos配置中心依赖 -->
<dependency><groupId>com.alibaba.boot</groupId><artifactId>nacos-config-spring-boot-starter</artifactId><version>0.2.10</version>
</dependency>

sentinel1.8.4引入springboot版本为2.5.12,启动项目会报错Caused by: java.lang.ClassNotFoundException: org.springframework.boot.context.properties.ConfigurationBeanFactoryMetadata
原因:在springboot2.4之后删掉了ConfigurationBeanFactoryMetadata
解决:将版本降至2.3.9.RELEASE

2、application.properties中添加nacos配置

# ============== ↓↓↓↓↓↓ 增加配置 -> 规则持久化到nacos ↓↓↓↓↓↓ ==============
server.port=8858
nacos.server-addr=127.0.0.1:8848
nacos.namespace=dev
nacos.group=sentinel-group
nacos.username=nacos
nacos.password=nacos

3、nacos配置

新增NacosConfig
@Configuration
public class NacosConfig {@Value("${nacos.server-addr}")private String serverAddr;@Value("${nacos.namespace}")private String namespace;@Value("${nacos.group}")public String group;@Value("${nacos.username}")private String username;@Value("${nacos.password}")private String password;@Beanpublic ConfigService nacosConfigService() throws Exception {Properties properties = new Properties();properties.put(PropertyKeyConst.SERVER_ADDR, this.serverAddr);properties.put(PropertyKeyConst.NAMESPACE, this.namespace);
//        properties.put(PropertyKeyConst.GROUP, this.group);properties.put(PropertyKeyConst.USERNAME, this.username);properties.put(PropertyKeyConst.PASSWORD, this.password);return ConfigFactory.createConfigService(properties);}
}
新增NacosConfigUtil
@Component
public final class NacosConfigUtil {@Resourceprivate NacosConfig nacosConfig;private static String GROUP_ID = null;@PostConstructpublic void init() {GROUP_ID = this.nacosConfig.group;}public static final String FLOW_DATA_ID_POSTFIX = "-sentinel-flow-rules";public static final String DEGRADE_DATA_ID_POSTFIX = "-sentinel-degrade-rules";public static final String SYSTEM_DATA_ID_POSTFIX = "-sentinel-system-rules";public static final String PARAM_FLOW_DATA_ID_POSTFIX = "-sentinel-param-flow-rules";public static final String AUTHORITY_DATA_ID_POSTFIX = "-sentinel-authority-rules";public static final String DASHBOARD_POSTFIX = "-sentinel-dashboard";private NacosConfigUtil() {}/*** 将规则序列化成JSON文本,存储到Nacos server中** @param configService nacos config service* @param app           应用名称* @param postfix       规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX* @param rules         规则对象* @throws NacosException 异常*/public static <T> void setRuleStringToNacos(ConfigService configService, String app, String postfix, List<T> rules) throws NacosException {AssertUtil.notEmpty(app, "app name cannot be empty");if (rules == null) {return;}List<Rule> ruleForApp = rules.stream().map(rule -> {RuleEntity rule1 = (RuleEntity) rule;System.out.println(rule1.getClass());Rule rule2 = rule1.toRule();System.out.println(rule2.getClass());return rule2;}).collect(Collectors.toList());String dataId = genDataId(app, postfix);/*** 俩种存储只是入参不同,为了满足功能的实现,存入nacos后,会有俩个配置,以后继续完善*/// 存储,控制微服务使用,即可以起到拦截作用,但是由于无法显示到控制台configService.publishConfig(dataId,NacosConfigUtil.GROUP_ID,JSON.toJSONString(ruleForApp));// 存储,给控制台显示使用,由于数据太多,会出现转化异常,虽然可以提供控制台显示,但是无法对微服务进行保护configService.publishConfig(dataId + DASHBOARD_POSTFIX,NacosConfigUtil.GROUP_ID,JSON.toJSONString(rules));}/*** 从Nacos server中查询响应规则,并将其反序列化成对应Rule实体** @param configService nacos config service* @param appName       应用名称* @param postfix       规则后缀 eg.NacosConfigUtil.FLOW_DATA_ID_POSTFIX* @param clazz         类* @param <T>           泛型* @return 规则对象列表* @throws NacosException 异常*/public static <T> List<T> getRuleEntitiesFromNacos(ConfigService configService, String appName, String postfix, Class<T> clazz) throws NacosException {String rules = configService.getConfig(genDataId(appName, postfix) + DASHBOARD_POSTFIX,NacosConfigUtil.GROUP_ID,3000);if (StringUtil.isEmpty(rules)) {return new ArrayList<>();}return JSON.parseArray(rules, clazz);}private static String genDataId(String appName, String postfix) {return appName + postfix;}
}

4、举例持久化流控规则

tips: 其它规则持久化参考本文案例源码

新增FlowRuleNacosProvider
@Component("flowRuleNacosProvider")
public class FlowRuleNacosProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {@Autowiredprivate ConfigService configService;@Overridepublic List<FlowRuleEntity> getRules(String appName) throws Exception {return NacosConfigUtil.getRuleEntitiesFromNacos(this.configService,appName,NacosConfigUtil.FLOW_DATA_ID_POSTFIX,FlowRuleEntity.class);}
}
新增FlowRuleNacosPublisher
@Component("flowRuleNacosPublisher")
public class FlowRuleNacosPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {@Autowiredprivate ConfigService configService;@Overridepublic void publish(String app, List<FlowRuleEntity> rules) throws Exception {NacosConfigUtil.setRuleStringToNacos(this.configService,app,NacosConfigUtil.FLOW_DATA_ID_POSTFIX,rules);}
}
修改FlowControllerV1
@RestController
@RequestMapping(value = "/v1/flow")
public class FlowControllerV1 {private final Logger logger = LoggerFactory.getLogger(FlowControllerV1.class);@Autowiredprivate InMemoryRuleRepositoryAdapter<FlowRuleEntity> repository;//    @Autowired
//    private SentinelApiClient sentinelApiClient;@Autowired@Qualifier("flowRuleNacosProvider")private DynamicRuleProvider<List<FlowRuleEntity>> ruleProvider;@Autowired@Qualifier("flowRuleNacosPublisher")private DynamicRulePublisher<List<FlowRuleEntity>> rulePublisher;@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 = sentinelApiClient.fetchFlowRuleOfMachine(app, ip, port);List<FlowRuleEntity> rules = ruleProvider.getRules(app);rules = repository.saveAll(rules);return Result.ofSuccess(rules);} catch (Throwable throwable) {logger.error("Error when querying flow rules", throwable);return Result.ofThrowable(-1, throwable);}}private <R> Result<R> checkEntityInternal(FlowRuleEntity entity) {if (StringUtil.isBlank(entity.getApp())) {return Result.ofFail(-1, "app can't be null or empty");}if (StringUtil.isBlank(entity.getIp())) {return Result.ofFail(-1, "ip can't be null or empty");}if (entity.getPort() == null) {return Result.ofFail(-1, "port can't be null");}if (StringUtil.isBlank(entity.getLimitApp())) {return Result.ofFail(-1, "limitApp can't be null or empty");}if (StringUtil.isBlank(entity.getResource())) {return Result.ofFail(-1, "resource can't be null or empty");}if (entity.getGrade() == null) {return Result.ofFail(-1, "grade can't be null");}if (entity.getGrade() != 0 && entity.getGrade() != 1) {return Result.ofFail(-1, "grade must be 0 or 1, but " + entity.getGrade() + " got");}if (entity.getCount() == null || entity.getCount() < 0) {return Result.ofFail(-1, "count should be at lease zero");}if (entity.getStrategy() == null) {return Result.ofFail(-1, "strategy can't be null");}if (entity.getStrategy() != 0 && StringUtil.isBlank(entity.getRefResource())) {return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");}if (entity.getControlBehavior() == null) {return Result.ofFail(-1, "controlBehavior can't be null");}int controlBehavior = entity.getControlBehavior();if (controlBehavior == 1 && entity.getWarmUpPeriodSec() == null) {return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");}if (controlBehavior == 2 && entity.getMaxQueueingTimeMs() == null) {return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");}if (entity.isClusterMode() && entity.getClusterConfig() == null) {return Result.ofFail(-1, "cluster config should be valid");}return null;}@PostMapping("/rule")@AuthAction(PrivilegeType.WRITE_RULE)public Result<FlowRuleEntity> apiAddFlowRule(@RequestBody FlowRuleEntity entity) {Result<FlowRuleEntity> checkResult = checkEntityInternal(entity);if (checkResult != null) {return checkResult;}entity.setId(null);Date date = new Date();entity.setGmtCreate(date);entity.setGmtModified(date);entity.setLimitApp(entity.getLimitApp().trim());entity.setResource(entity.getResource().trim());try {entity = repository.save(entity);publishRules(entity.getApp(), entity.getIp(), entity.getPort());return Result.ofSuccess(entity);} catch (Throwable t) {Throwable e = t instanceof ExecutionException ? t.getCause() : t;logger.error("Failed to add new flow rule, app={}, ip={}", entity.getApp(), entity.getIp(), e);return Result.ofFail(-1, e.getMessage());}}@PutMapping("/save.json")@AuthAction(PrivilegeType.WRITE_RULE)public Result<FlowRuleEntity> apiUpdateFlowRule(Long id, String app,String limitApp, String resource, Integer grade,Double count, Integer strategy, String refResource,Integer controlBehavior, Integer warmUpPeriodSec,Integer maxQueueingTimeMs) {if (id == null) {return Result.ofFail(-1, "id can't be null");}FlowRuleEntity entity = repository.findById(id);if (entity == null) {return Result.ofFail(-1, "id " + id + " dose not exist");}if (StringUtil.isNotBlank(app)) {entity.setApp(app.trim());}if (StringUtil.isNotBlank(limitApp)) {entity.setLimitApp(limitApp.trim());}if (StringUtil.isNotBlank(resource)) {entity.setResource(resource.trim());}if (grade != null) {if (grade != 0 && grade != 1) {return Result.ofFail(-1, "grade must be 0 or 1, but " + grade + " got");}entity.setGrade(grade);}if (count != null) {entity.setCount(count);}if (strategy != null) {if (strategy != 0 && strategy != 1 && strategy != 2) {return Result.ofFail(-1, "strategy must be in [0, 1, 2], but " + strategy + " got");}entity.setStrategy(strategy);if (strategy != 0) {if (StringUtil.isBlank(refResource)) {return Result.ofFail(-1, "refResource can't be null or empty when strategy!=0");}entity.setRefResource(refResource.trim());}}if (controlBehavior != null) {if (controlBehavior != 0 && controlBehavior != 1 && controlBehavior != 2) {return Result.ofFail(-1, "controlBehavior must be in [0, 1, 2], but " + controlBehavior + " got");}if (controlBehavior == 1 && warmUpPeriodSec == null) {return Result.ofFail(-1, "warmUpPeriodSec can't be null when controlBehavior==1");}if (controlBehavior == 2 && maxQueueingTimeMs == null) {return Result.ofFail(-1, "maxQueueingTimeMs can't be null when controlBehavior==2");}entity.setControlBehavior(controlBehavior);if (warmUpPeriodSec != null) {entity.setWarmUpPeriodSec(warmUpPeriodSec);}if (maxQueueingTimeMs != null) {entity.setMaxQueueingTimeMs(maxQueueingTimeMs);}}Date date = new Date();entity.setGmtModified(date);try {entity = repository.save(entity);if (entity == null) {return Result.ofFail(-1, "save entity fail: null");}publishRules(entity.getApp(), entity.getIp(), entity.getPort());return Result.ofSuccess(entity);} catch (Throwable t) {Throwable e = t instanceof ExecutionException ? t.getCause() : t;logger.error("Error when updating flow rules, app={}, ip={}, ruleId={}", entity.getApp(),entity.getIp(), id, e);return Result.ofFail(-1, e.getMessage());}}@DeleteMapping("/delete.json")@AuthAction(PrivilegeType.WRITE_RULE)public Result<Long> apiDeleteFlowRule(Long id) {if (id == null) {return Result.ofFail(-1, "id can't be null");}FlowRuleEntity oldEntity = repository.findById(id);if (oldEntity == null) {return Result.ofSuccess(null);}try {repository.delete(id);} catch (Exception e) {return Result.ofFail(-1, e.getMessage());}try {publishRules(oldEntity.getApp(), oldEntity.getIp(), oldEntity.getPort());return Result.ofSuccess(id);} catch (Throwable t) {Throwable e = t instanceof ExecutionException ? t.getCause() : t;logger.error("Error when deleting flow rules, app={}, ip={}, id={}", oldEntity.getApp(),oldEntity.getIp(), id, e);return Result.ofFail(-1, e.getMessage());}}//    private CompletableFuture<Void> publishRules(String app, String ip, Integer port) {//        List<FlowRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
//        return sentinelApiClient.setFlowRuleOfMachineAsync(app, ip, port, rules);
//    }private void publishRules(String app, String ip, Integer port) {//        List<AuthorityRuleEntity> rules = repository.findAllByMachine(MachineInfo.of(app, ip, port));
//        return sentinelApiClient.setAuthorityRuleOfMachine(app, ip, port, rules);List<FlowRuleEntity> rules = repository.findAllByApp(app);try {rulePublisher.publish(app, rules);} catch (Exception e) {e.printStackTrace();}}
}

四、本文案例源码

https://gitee.com/zhengqingya/java-workspace


今日分享语句:
鸡蛋,从外打破是食物,从内打破是生命,人生也是如此,从外打破是压力,从内打破是成长。

SpringCloud(14) Sentinel 1.8.4 规则持久化到Nacos相关推荐

  1. Sentinel Dashboard 中修改规则同步到 Nacos

    点击蓝色"程序猿DD"关注我哟 加个"星标",不忘签到哦 上一篇我们介绍了如何通过改造Sentinel Dashboard来实现修改规则之后自动同步到Apoll ...

  2. Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Nacos

    上一篇我们介绍了如何通过改造Sentinel Dashboard来实现修改规则之后自动同步到Apollo.下面通过这篇,详细介绍当使用Nacos作为配置中心之后,如何实现Sentinel Dashbo ...

  3. Sentinel(二十六)之Sentinel Dashboard中修改规则同步到Nacos

    转载自  Spring Cloud Alibaba基础教程:Sentinel Dashboard中修改规则同步到Nacos 上一篇我们介绍了如何通过改造Sentinel Dashboard来实现修改规 ...

  4. 【SpringCloud】Spring cloud Alibaba Sentinel 规则持久化

    1.概述 服务重启后,页面上配置的规则就消失了,生产上是一样要持久化的. 将限流配置规则持久化进Nacos保存,只要刷新8401某个rest地址,sentinel控制台的流控规则就能看到, I只要Na ...

  5. Sentinel 规则持久化到 apollo 配置中心

    Sentinel 规则默认是存储在内存中的,只要服务重启之后对应的规则也会消失,实际的生产中肯定是不允许这种操作,因此 Sentinel 官方推荐在生产架构中使用第三方数据源作为永久存储中心,比如 n ...

  6. SpringCloud Alibaba Sentinel实现熔断与限流

    服务使用中的各种问题 服务雪崩   服务降级   服务熔断   服务限流 安装Sentinel sentinel和项目必须在同一个ip下   sentinel组件由2部分构成     后台     前 ...

  7. SpringCloud Alibaba Sentinel实现熔断与限流(下)

    在上一篇讲了sentinel的介绍,安装Sentinel控制台.初始化演示工以及程流控规则 接下来学习熔断规则,热点key限流,系统规则,@SentinelResource注解,服务熔断功能以及规则持 ...

  8. springcloud(十六)--SpringCloud Alibaba Sentinel实现熔断与限流

    Sentinel实现熔断与限流 一.Sentinel 二.安装Sentinel控制台 Sentinel安装步骤: ①下载 ②运行命令 ③访问sentinel管理界面 三.初始化演示工程 1.启动Nao ...

  9. Sentinel动态推拉数据持久化同步到Nacos

    前言 在我们使用Sentinel做熔断限流等操作时,一些设置好的配置默认是存放在当前服的内存中的,那么也就意味着每次重启服务,这些配置好的配置就会消失.在我们搭建微服务架构做测试的时候不是很友好.大家 ...

最新文章

  1. perl 编程 - 判断系统进程是否活着的方法
  2. Java面试高Spring Boot+Sentinel+Nacos高并发已撸完
  3. 思科安全:加密流量威胁检测、加密流量威胁和恶意软件检测、识别无线干扰或威胁、Talos 情报源可加强对已知和新型威胁的防御、分布式安全异常检测...
  4. 关系型数据库的超键、候选键、主键
  5. 树莓派4B装载ROS系统启动摄像头
  6. 45岁的 SQL 语言要被淘汰了?
  7. android京东加入购物车效果,京东360buy 手机项目的“加入购物车”动画效果研究...
  8. SAP 电商云 Spartacus UI 路由事件监控
  9. nssl1478-题【dp】
  10. 语法分析——自上而下
  11. 买房贷款收入证明怎么开?
  12. C语言库函数大全及应用实例三
  13. .NET Core中延迟单例另一种写法【.NET Core和.NET Framework的beforefieldinit差异】
  14. Jquery简单幻灯片
  15. ASP.NET-Request对象
  16. ICML 2022 | 稀疏双下降:网络剪枝也能加剧模型过拟合?
  17. anbox android 镜像,Anbox:容器中的 Android
  18. matlab 浮雕算法,photoshop图像滤镜——浮雕算法(含matlab代码)
  19. Amlogic连续三年居中国OTT芯片市占率第一
  20. Python如何判断质数(素数)

热门文章

  1. Python @property 详解
  2. 命令行 笔记本键盘禁用_如何在 Ubuntu 20.04 上禁用坞站(dock) | Linux 中国
  3. 西京学院学位计算机题库和答案,西京学院 学位英语 普通英语 精彩试题整理.doc...
  4. Android8.1 开关VOLTE流程分析
  5. 动力节点『lol版』Java学习路线图(七)架构师提升必备技术点
  6. 深度linux 内核符号表,linux 内核符号表
  7. 计算机软件优质课,计算机课公开课ppt
  8. 互联网学习记录:三件套_Javascript
  9. linux系统cpu性能测试工具
  10. cpu性能指标和测试工具