Sentinel 规则持久化,基于Redis持久化【附带源码】

B站视频讲解

学习链接🔗

文章目录

  • 一、理论
  • 二、实践
    • 2-1、dashboard 请求Redis
      • 2-1-1、依赖、配置文件引入
      • 2-1-2、常量定义
      • 2-1-3、改写唯一id
      • 2-1-4、新Provider和Publisher
      • 2-1-5、改写V2
    • 2-2、应用服务改造
      • 2-2-1、依赖、配置文件引入
      • 2-2-2、注册监听器
  • 三、源码获取
    • 3-1、使用
    • 3-2、获取方式
  • 四、参考


上一篇讲Sentinel的时候,是用dashboard直接和服务进行交互,实时的新增/删除限流规则,所有的规则都存储在应用服务的内存中,每次重启服务之后再刷新dashboard就没有对应规则信息了。

这当然不是我们希望看到的,如果想要长久的保存规则,有且只有一个办法,那就是规则数据持久化。


一、理论


  1. 既然dashboard可以把规则推送到服务端,那服务端就可以拿到规则去持久化到硬盘上(文件、MySQL…),怎么说呢?这看起来不是个好办法,首先它很low,其次也不好解决分布式系统数据一致性的问题。
  2. 那换一种思路,dashboard先把规则推送给A,再由A把规则下发到各个具体的应用服务。这样A就相当于一种中心存储,解决了数据存储的问题,同时A实时下发给应用服务解决了数据一致性的问题。

这个A,官方给出了几种实现Nacos、ZooKeeper、Apollo、Redis。(理论上是可以自己去重写做到任何实现)


第一种方式就不推荐了,下面基于方式二来做实践,这里选用Redis来,主要是目前电脑只安装了Redis,原理是一样的。

下面是官方给出的图,要理解,是先把规则给到A,再由A去下发规则。(所以需要修改dashboard源码,让它先请求A)


想深入了解的可以参看下面的文档:

  1. https://github.com/alibaba/Sentinel/wiki/动态规则扩展
  2. https://github.com/alibaba/Sentinel/wiki/在生产环境中使用-Sentinel

二、实践


基于上面的分析,需要分两步改造

  1. 让dashboard把规则数据推送给Redis
  2. 应用服务接受Redis的下发(基于Redis的发布订阅功能)

注:会在Redis定义一个Key用来存储最终的规则数据,还会定义一个通道用来实时推送规则数据


2-1、dashboard 请求Redis


从Github下载dashboard源码:https://github.com/alibaba/Sentinel/releases

默认情况下,dashboard限流策略请求的是这个 v1 接口,官方还提供了一个 v2,这个v2就是持久化的接口,基于不同的持久化策略,只需要在 v2的版本里面替换对应的 DynamicRuleProvider、DynamicRulePublisher
在这里插入图片描述


2-1-1、依赖、配置文件引入


1、Redis-starter 引入

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>${spring.boot.version}</version>
</dependency>

2、配置文件修改

spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.database=0

3、Redis配置

@Configuration
public class RedisConfig {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();redisTemplate.setConnectionFactory(factory);redisTemplate.setEnableTransactionSupport(true);GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();redisTemplate.setValueSerializer(jsonRedisSerializer);redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(jsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

2-1-2、常量定义


public final class Constants {// 最终规则是存储的keypublic static final String RULE_FLOW_PREFIX = "sentinel:rule:flow:xdx";// Redis的订阅发布功能,需要一个通道public static final String RULE_FLOW_CHANNEL_PREFIX = "sentinel:channel:flow:xdx";// 每一个规则都需要唯一id,基于Redis生成idpublic static final String RULE_FLOW_ID_KEY = "sentinel:id:flow:xdx";
}

2-1-3、改写唯一id


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;@Component
public class RedisIdGenerator {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;public long nextId(String key) {return redisTemplate.opsForValue().increment(key, 1);}
}

在这里插入图片描述


2-1-4、新Provider和Publisher


Provider的目的是读取Redis的内存数据

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRuleProvider;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;import java.util.Collections;
import java.util.List;import static com.alibaba.csp.sentinel.dashboard.xdx.Constants.RULE_FLOW_PREFIX;@Component("flowRuleRedisProvider")
public class FlowRuleRedisProvider implements DynamicRuleProvider<List<FlowRuleEntity>> {private final Logger logger = LoggerFactory.getLogger(FlowRuleRedisProvider.class);@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Overridepublic List<FlowRuleEntity> getRules(String appName) throws Exception {Assert.notNull(appName, "应用名称不能为空");logger.info("拉取redis流控规则开始: {}", appName);String key = RULE_FLOW_PREFIX;String ruleStr = (String)redisTemplate.opsForValue().get(key);if(StringUtils.isEmpty(ruleStr)) {return Collections.emptyList();}List<FlowRuleEntity> rules = JSON.parseArray(ruleStr, FlowRuleEntity.class);logger.info("拉取redis流控规则成功, 规则数量: {}", rules.size());return rules;}
}

每次规则变动,都把最新规则存到Redis里面去,并使用Redis通道发布

import com.alibaba.csp.sentinel.dashboard.datasource.entity.rule.FlowRuleEntity;
import com.alibaba.csp.sentinel.dashboard.rule.DynamicRulePublisher;
import com.alibaba.fastjson.JSON;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;import java.util.List;import static com.alibaba.csp.sentinel.dashboard.xdx.Constants.RULE_FLOW_CHANNEL_PREFIX;
import static com.alibaba.csp.sentinel.dashboard.xdx.Constants.RULE_FLOW_PREFIX;@Component("flowRuleRedisPublisher")
public class FlowRuleRedisPublisher implements DynamicRulePublisher<List<FlowRuleEntity>> {private final Logger logger = LoggerFactory.getLogger(FlowRuleRedisPublisher.class);@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Overridepublic void publish(String app, List<FlowRuleEntity> rules) throws Exception {Assert.notNull(app, "应用名称不能为空");Assert.notEmpty(rules, "策略规则不为空");logger.info("推送流控规则开始, 应用名: {}, 规则数量: {}", app, rules.size());String ruleKey = RULE_FLOW_PREFIX;String ruleStr = JSON.toJSONString(rules);// 数据存储redisTemplate.opsForValue().set(ruleKey, ruleStr);// 数据发布redisTemplate.convertAndSend(RULE_FLOW_CHANNEL_PREFIX, ruleStr);}
}

2-1-5、改写V2


  1. 刚刚说默认是请求V1版本,这里为了简单,直接把V1的@RequestMapping注释,把V2的@RequestMapping改成V1(可以改前端,让它请求到V2)
  2. 把新 V1的Publisher和Provider改成新的Redis版本
  3. 下图也是每个类的位置

在这里插入图片描述


2-2、应用服务改造


  1. https://github.com/alibaba/Sentinel/wiki/动态规则扩展
  2. Sentinel 官方已经做了Redis适配,使用起来也很简单了

2-2-1、依赖、配置文件引入


1、新增pom文件

<dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-datasource-redis</artifactId><version>1.8.6</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、配置文件

spring:redis:host: 127.0.0.1port: 6379

3、Redis 配置文件(和上面一样)

@Configuration
public class ConfigRedis {@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();redisTemplate.setConnectionFactory(factory);redisTemplate.setEnableTransactionSupport(true);GenericJackson2JsonRedisSerializer jsonRedisSerializer = new GenericJackson2JsonRedisSerializer();StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();redisTemplate.setValueSerializer(jsonRedisSerializer);redisTemplate.setKeySerializer(stringRedisSerializer);redisTemplate.setHashKeySerializer(stringRedisSerializer);redisTemplate.setHashValueSerializer(jsonRedisSerializer);redisTemplate.afterPropertiesSet();return redisTemplate;}
}

2-2-2、注册监听器


直接在启动类里面改造就好了

@SpringBootApplication
public class App11 implements ApplicationRunner {public static void main(String[] args) {SpringApplication.run(App11.class, args);}public static final String RULE_FLOW_PREFIX = "sentinel:rule:flow:xdx";public static final String RULE_FLOW_CHANNEL_PREFIX = "sentinel:channel:flow:xdx";@Overridepublic void run(ApplicationArguments args)  {Converter<String ,List<FlowRule>> parser = source -> {List<FlowRule> flowRules = new ArrayList<>();if (source != null) {String replace = source.replace("\\", "");String substring = replace.substring(1, replace.length() - 1);flowRules = JSON.parseArray(substring, FlowRule.class);}return flowRules;};RedisConnectionConfig config = RedisConnectionConfig.builder().withHost("127.0.0.1").withPort(6379).build();ReadableDataSource<String, List<FlowRule>> redisDataSource = new RedisDataSource<>(config, RULE_FLOW_PREFIX, RULE_FLOW_CHANNEL_PREFIX, parser);FlowRuleManager.register2Property(redisDataSource.getProperty());System.out.println("redis-sentinel-持久化开启");}
}

三、源码获取


3-1、使用


下面是修改好的sentinel-dashboard和对应的应用服务,只需要修改两个服务中的Redis连接地址就可以使用,如果你的Redis是 默认的127.0.0.1 和 6379 则无需修改。

在这里插入图片描述


3-2、获取方式


  1. 关注微信公众号:小道仙97
  2. 回复关键字:Sentinel_xdx97

四、参考


  • https://github.com/all4you/sentinel-tutorial/blob/master/sentinel-practice/sentinel-persistence-rules/sentinel-persistence-rules.md
  • https://sentinelguard.io/zh-cn/blog/use-sentinel-dashboard-in-production.html
  • https://github.com/alibaba/Sentinel/tree/master/sentinel-extension/sentinel-datasource-redis
  • https://github.com/alibaba/Sentinel/wiki/%E5%8A%A8%E6%80%81%E8%A7%84%E5%88%99%E6%89%A9%E5%B1%95
  • https://github.com/alibaba/Sentinel/tree/master/sentinel-extension/sentinel-datasource-redis
  • https://www.jianshu.com/p/997a2255ff23
  • https://github.com/alibaba/Sentinel/wiki/%E5%9C%A8%E7%94%9F%E4%BA%A7%E7%8E%AF%E5%A2%83%E4%B8%AD%E4%BD%BF%E7%94%A8-Sentinel
  • https://github.com/alibaba/Sentinel/wiki/Sentinel-%E6%8E%A7%E5%88%B6%E5%8F%B0%EF%BC%88%E9%9B%86%E7%BE%A4%E6%B5%81%E6%8E%A7%E7%AE%A1%E7%90%86%EF%BC%89#%E8%A7%84%E5%88%99%E9%85%8D%E7%BD%AE
  • https://blog.csdn.net/qq_42714869/article/details/94553378

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/726432.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Talk|加州大学圣地亚哥分校程旭欣:视觉反馈下足式机器人的全身操作与运动

本期为TechBeat人工智能社区第576期线上Talk。 北京时间3月6日(周三)20:00&#xff0c;加州大学圣地亚哥分校博士生—程旭欣的Talk已准时在TechBeat人工智能社区开播&#xff01; 他与大家分享的主题是: “视觉反馈下足式机器人的全身操作与运动”&#xff0c;向大家系统地介绍…

智能驾驶规划控制理论学习07-规划算法整体框架

一、解耦合策略 1、路径-速度解耦策略概述 路径-速度解耦指的是将车辆的运动分成路径规划和速度规划两部分&#xff0c;对两个部分分别进行研究。 路径规划&#xff1a; 假设环境是“静态的”&#xff0c;将障碍物投射到参考路径上&#xff0c;并规划一条避开它们的路径&…

【C语言】linux内核napi_gro_receive和netif_napi_add

napi_gro_receive 一、注释 // napi_gro_receive是网络设备接口的一个函数&#xff0c;它被NAPI&#xff08;New API&#xff09;网络轮询机制使用&#xff0c;用于接收和处理接收到的数据包。 // 这个函数通过通用接收分组&#xff08;GRO&#xff0c;Generic Receive Offlo…

Ubuntu安装conda以后,给jupyter安装C++内核

前言 大家都知道&#xff0c;jupyter notebook 可以支持python环境&#xff0c;可以在不断点调试的情况下&#xff0c;打印出当前结果&#xff0c;如果代码错了也不影响前面的内容。于是我就想有没有C环境的&#xff0c;结果还真有。 参考文章&#xff1a; 【分享】Ubuntu安装…

【金三银四的季节看下Java ORM的走向和性能对比】总结

写在最后 经过将近一周时间的框架收集、学习、实验、编码、测试市面上常见的ORM框架&#xff0c;过程中拜读了很多作者的博文、样例&#xff0c;学习很多收获很多。 重新梳理下整理的框架&#xff1a;mybatis-plus、lazy、sqltoy、mybatis-flex、easy-query、mybatis-mp、jpa、…

什么是工业交换机?

如今&#xff0c;工业交换机在能源、环保、交通、智慧城市监控等各个行业都发挥着至关重要的作用&#xff0c;其需求也日益增长。本文将全面介绍工业交换机&#xff0c;帮助你进一步加深了解。 什么是工业交换机&#xff1f; 工业交换机&#xff0c;又称工业以太网交换机&…

《探索自动驾驶技术的前景与挑战》

自动驾驶技术,作为现代科技的一大突破,正逐渐改变着我们的交通方式、生活方式以及整个社会结构。本文将围绕自动驾驶技术的现状、优势、局限性以及未来发展趋势展开探讨。 自动驾驶技术的现状概述 自动驾驶技术作为当今科技领域的一项前沿技术,已经取得了巨大的进展并在不同…

安卓开发之资源概述、优劣分析与优化方案

摘要 随着智能手机的普及&#xff0c;Android操作系统已成为全球最广泛使用的移动平台之一。在Android应用开发中&#xff0c;资源管理是构建高效、响应迅速且用户友好的应用程序的关键要素。 本文主要探讨了安卓应用程序开发过程中的资源管理机制&#xff0c;包括其基本结构、…

一键清除JavaScript代码中的注释:使用正则表达式实现

这个正则表达式可以有效地匹配 JavaScript 代码中的各种注释&#xff0c;并且跳过了以 http: 或 https: 开头的链接。 /\/\*[\s\S]*?\*\/|\/\/[^\n]*|<!--[\s\S]*?-->|(?<!http:|https:)\/\/[^\n]*/gvscode 实战&#xff0c;ctrlF 调出查找替换工具&#xff0c;点…

如何把网页调用变为代码调用

1.背景 最近有一个需求&#xff0c;猜测一段十六进制流的校验方式&#xff0c;挨个尝试非常耗时&#xff0c;需要写代码&#xff0c;调用网页上的功能。 2.解决方案 可以使用Python的 requests 库来发起HTTP请求&#xff0c;并通过POST请求将数据发送给服务器进行计算CRC校验和…

【备战蓝桥杯系列】Java组国二选手笔记一:蓝桥杯中的常用语法特性

蓝桥杯Java国二选手笔记一&#xff1a;蓝桥杯中的常用语法特性 前言 参加了好几次蓝桥杯了&#xff0c;C组参加了&#xff0c;Java也参加过&#xff0c;也会用python刷算法。下面给出常用的Java语法特性在蓝桥杯中的使用&#xff0c;以及常见的需要注意的Java语法规范。有准备…

【MySQL】-知识点整理

1、存储引擎 -- 查询数据库支持的存储引擎 show engines; -- 查询当前数据库使用的存储引擎 show variables like %storage_engines%; 主要的存储引擎说明&#xff1a; 1&#xff09;MyISAM&#xff1a;无外键、表锁、所有索引都是非聚簇索引、无事务、记录表总条数、删除表…

基于el-tree实现懒加载穿梭条

一、关键代码 <template><div><!-- 左侧待选列表 --><div class"left-box"><p>待选列表</p><el-input placeholder"输入关键词过滤" v-model"leftFilterText" clearable/><el-treeref"tree…

便捷在线导入:完整Axure元件库集合,让你的设计更高效!

Axure元件库包含基本的工具组件&#xff0c;可以使原型绘制节省大量的重复工作&#xff0c;保持整个设计页面的一致性和标准化&#xff0c;同时显得专业。Axure元件库就像我们日常生活中的门把手、自行车踏板和桌子上的螺丝钉&#xff0c;需要组装才能使用。作为一名成熟的产品…

【Web - 框架 - Vue】随笔 - Vue的简单使用(02) - 快速上手

【Web - 框架 - Vue】随笔 - Vue的简单使用(02) - 快速上手 Vue模板代码 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>Vue模板</title> </head> <body> <div id"…

redis 性能优化二

前言 性能优化的第二篇文章&#xff0c;将重点讲一下Redis 的响应延迟&#xff0c;响应延迟如何对redis 进行优化。这个延迟不是说一个命令或者几个命令变慢了&#xff0c;延迟了几秒&#xff0c;就说Redis 变慢了。在不同的软硬件环境下&#xff0c;Redis 本身的绝对性能并不…

基于STM32开路清障车控制系统设计

目 录 摘 要 I Abstract II 引 言 1 1总体方案论证与设计 3 1.1设计方案 3 1.2主控模块的选型和论证 3 2系统硬件电路设计 5 2.1主控模块设计 5 2.1.1 STM32单片机概述 5 2.1.2 STM32单片机最小系统电路 5 2.2 MCU主要实现功能 6 2.3火焰传感器 7 2.4超声波模块 8 2.5驱动模块…

Docker-自定义镜像

目录 1 前言 2 构建java应用的步骤及镜像结构图 2.1 构建步骤 2.2 镜像结构图 3 Dockerfile常用指令 4 Dockerfile的内容举例 4.1 一般形式 4.2 一般形式的优化 5 构建镜像 5.1 指令 5.2 实操 5.2.1 加载jdk镜像(基础镜像) 5.2.2 构建我们的镜像 5.2.3 使用我们的…

SpringCloud微服务-RabbitMQ快速入门

文章目录 RabbitMQ快速入门1、什么是MQ&#xff1f;2、RabbitMQ概述3、RabbitMQ的结构和概念4、常见消息模型5、HelloWorld RabbitMQ快速入门 1、什么是MQ&#xff1f; MQ &#xff08;MessageQueue&#xff09;&#xff0c;中文是消息队列&#xff0c;字面来看就是存放消息的…

Linux nmcli命令使用教程(nmcli指令)

文章目录 先区分两个概念&#xff1a;网络设备和网络连接网络设备网络连接网络连接的UUID nmcli可以为一个网络设备创建多个网络连接&#xff0c;但同一时刻只有一个能生效 Mastering Network Management with nmcli in Linux&#xff08;掌握Linux中使用nmcli进行网络管理&…