首页 > 其他分享 >基于Nacos实现Sentinel规则持久化

基于Nacos实现Sentinel规则持久化

时间:2024-05-23 23:25:34浏览次数:25  
标签:持久 配置 Nacos 规则 Sentinel groupId 服务端

基于Nacos实现Sentinel规则持久化

一、Sentinel使用痛点

SpringCloudAlibaba帮我们提供了微服务的限流、熔断、降级组件Sentinel。并且它的功能非常强大,使用起来也非常方便,只需要给需要限流的资源添加注解,配置对应的规则,就能实现效果。(使用可以参考Sentinel使用)但是有个问题就是Sentinel的规则是保存在客户端的内存中,控制台(服务端)查询规则也是基于客户端内存查询。

这样就存在一个很严重的问题,如果客户端发生了重启那么配置的众多规则都会失效。想想都觉得很严重,谁还敢在生产环境使用它。那么基于这个问题,我们有多种方案可以来解决。

二、解决方案

2.1 保存本地文件

既然是担心规则保存在客户端内存中会丢失,那么我们可以将规则持久化到本地文件,但是这样也有一个问题,如果微服务是高可用部署,有多个实例节点,那么保存到本地文件就不可取了。

2.2 保存数据库

将规则持久化到数据库中,这样多个节点访问同一个数据库也能拿到配置,这样的缺点是如果规则变化从数据库中直接修改,微服务则没那么容易感知到变化,不过也不是解决不了,可以使用canel组件,监听mysql的binlog日志,从而刷新规则,但这这样又要引入新的中间件,增加了系统的复杂性。

2.3 保存到Nacos

我们知道nacos的客户端在启动时会主动从服务端拉取一次配置,之后会通过延迟定时任务拉取配置,同时对配置文件配置监听器。双层保证服务端的变化能被客户端感知到,基于Nocos本来的特性,再整合Sentinel的扩展点,我们就可以实现如下图的结构。
在Nacos服务端或者Sentinel控制台修改配置,都能将规则推送到Sentinel客户端。并且在Nacos服务端修改配置规则Sentinel控制台的规则会发生变化,在Sentinel控制台修改规则,Naocs的配置文件就会发生变化。
在这里插入图片描述

三、规则持久化到Nacos

梳理一下配置变更的两条线

  1. Nacos服务端修改配置,规则同步到Sentinel客户端及Sentinel控制台
  2. Sentinel控制台修改配置,规则同步到Sentinel客户端和Nacos服务端

3.1 Nacos服务端修改配置

  1. 我们在使用nacos作为规则持久化时需要引入一下相关依赖。
 <!--sentinel -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-sentinel</artifactId>
        </dependency>

        <!--sentinel持久化 -->
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-nacos</artifactId>
        </dependency>
    
        <!-- nacos服务注册与发现 -->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
  1. spring-cloud-starter-alibaba-sentinel这个依赖会包含spring-cloud-starter-alibaba-sentinel-datasource
    在这里插入图片描述
  2. spring-cloud-starter-alibaba-sentinel-datasource依赖中引入了关键类NacosDataSourceFactoryBean
    在这里插入图片描述
  3. NacosDataSourceFactoryBean的构造方法中实例化了NacosDataSource
public class NacosDataSourceFactoryBean implements FactoryBean<NacosDataSource> {
public NacosDataSource getObject() throws Exception {
		// 中间代码省略...
      return new NacosDataSource(properties, this.groupId, this.dataId, this.converter);
    }
}
  1. NacosDataSource由sentinel-datasource-nacos依赖引入
    在这里插入图片描述
  2. NacosDataSource的构造方法中会定义监听器,并且将监听器和配置文件绑定,这样当Nacos服务端修改配置后,客户端就能拿到最新的规则,并且将规则更新内存中。同时会先从Nacos服务拉去一次配置做初始化。
public NacosDataSource(final Properties properties, final String groupId, final String dataId, Converter<String, T> parser) {
        super(parser);
        this.pool = new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue(1), new NamedThreadFactory("sentinel-nacos-ds-update", true), new DiscardOldestPolicy());
        this.configService = null;
        if (!StringUtil.isBlank(groupId) && !StringUtil.isBlank(dataId)) {
            AssertUtil.notNull(properties, "Nacos properties must not be null, you could put some keys from PropertyKeyConst");
            this.groupId = groupId;
            this.dataId = dataId;
            this.properties = properties;
            // 1.定义监听器,当配置发生变更监听器就能获取最新的配置
            this.configListener = new Listener() {
                public Executor getExecutor() {
                    return NacosDataSource.this.pool;
                }

                public void receiveConfigInfo(String configInfo) {
                    RecordLog.info("[NacosDataSource] New property value received for (properties: {}) (dataId: {}, groupId: {}): {}", new Object[]{properties, dataId, groupId, configInfo});
                    T newValue = NacosDataSource.this.parser.convert(configInfo);
                    NacosDataSource.this.getProperty().updateValue(newValue);
                }
            };
            // 2.将监听器和配置文件绑定
            this.initNacosListener();
            // 3.从Nacos服务端拉取配置放在内存中
            this.loadInitialConfig();
        } else {
            throw new IllegalArgumentException(String.format("Bad argument: groupId=[%s], dataId=[%s]", groupId, dataId));
        }
    }

3.2 Sentinel控制台修改配置

  1. Sentinel控制台发布规则后会调用Sentinel客户端的ModifyRulesCommandHandler,将修改的规则传过来。

  2. ModifyRulesCommandHandler的handle方法中是真正的处理逻辑,这里以流控规则为例,其他规则一样只是代码没展示。在Handle方法中会先将最新的规则加载到内存中,并且进行规则的持久化处理。

@CommandMapping(name = "setRules", desc = "modify the rules, accept param: type={ruleType}&data={ruleJson}")
public class ModifyRulesCommandHandler implements CommandHandler<String> {
@Override
    public CommandResponse<String> handle(CommandRequest request) {
    	// 省略部分代码...
        if (FLOW_RULE_TYPE.equalsIgnoreCase(type)) {
            List<FlowRule> flowRules = JSONArray.parseArray(data, FlowRule.class);
            // 1.将规则加载到内存中
            FlowRuleManager.loadRules(flowRules);
            // 2.规则持久化(如果增加了扩展,默认没有实现)
            if (!writeToDataSource(getFlowDataSource(), flowRules)) {
                result = WRITE_DS_FAILURE_MSG;
            }
            return CommandResponse.ofSuccess(result);
        }
}
  1. 上面的持久化最终会调用到我们自己实现的Nacos实现类中,最终将配置发布到Nacos服务端。
public class NacosWritableDataSource<T> implements WritableDataSource<T> {
@Override
    public void write(T t) throws Exception {
        lock.lock();
        try {
            configService.publishConfig(dataId, groupId, this.configEncoder.convert(t), ConfigType.JSON.getType());
        } finally {
            lock.unlock();
        }
    }
}

3.3 Nacos数据源整合到Sentinel中

  1. application.yml中需要对Nacos数据进行配置(以流控规则为例)
spring:
  application:
    name: sentinel-rule-push-demo  #微服务名称
  #配置nacos注册中心地址
  cloud:
    nacos:
      discovery:
        server-addr: 127.0.0.1:8848
    sentinel:
      transport:
        # 添加sentinel的控制台地址
        dashboard: 127.0.0.1:8080
      datasource:
        flow-rules:
          nacos:
            server-addr: 127.0.0.1:8848
            dataId: ${spring.application.name}-flow
            groupId: SENTINEL_GROUP   # 注意groupId对应Sentinel Dashboard中的定义
            data-type: json
            rule-type: flow
  1. 将Nacos数据源注册为Sentinel的写数据源
public class NacosDataSourceListener implements ApplicationListener<ContextRefreshedEvent> {
    @Autowired
    private SentinelProperties sentinelProperties;
	@Override
    public void onApplicationEvent(ContextRefreshedEvent event) {
    	// 1.获取流控规则数据源信息
        NacosDataSourceProperties nacosDataSourceProperties = sentinelProperties.getDatasource().get("flow-rules").getNacos();
        // 2.初始化流控规则数据源
        WritableDataSource<List<FlowRule>> writableDataSource = new NacosWritableDataSource<>(
                nacosDataSourceProperties.getServerAddr(), nacosDataSourceProperties.getGroupId(), nacosDataSourceProperties.getDataId(), JSON::toJSONString);
        // 将Nacos数据源注册为Sentinel写数据源
        WritableDataSourceRegistry.registerFlowDataSource(writableDataSource);
    }
}

标签:持久,配置,Nacos,规则,Sentinel,groupId,服务端
From: https://blog.csdn.net/qq_45003354/article/details/139131592

相关文章

  • nacos启动异常和动态配置未生效
    最近打算研究一下nacos动态配置的原理,于是开始照着Nacos官网快速入门。但是发现在和SpringBoot以及SpringCloud适配启动的时候,总是报错无法启动,于是深入排查了一下并作以记录。1.nacos和SpringBoot启动报错Invaliddefault:publicabstractcom.alibaba.nacos.api.config.Con......
  • Nacos的配置管理
    为什么需要配置管理?在单体应用中,配置管理可能不是什么大的事情,通常会以配置文件的方式。常见的方法比如将配置通过打包脚本打入应用包中,或者直接放到运行应用的服务器的特定目录下,或者存储到数据库中。这种方式在传统的单体应用中简单有效,但是也会有些比较棘手的问题,比如:配置......
  • Nacos的服务分级模型
    分级模型为了提升整个系统的容灾性,Nacos引入了地域(Zone)的概念,如上图中的北京、上海和杭州。把同一个服务的多个实例部署到不同地域的机房中(鸡蛋分开不同的篮子放);又把在同一个地域的机房的多个服务实例称为集群(Cluster)。比如,杭州机房的2个用户服务user-servi......
  • Nacos注册中心
    Nacos是springcloud的扩展,注册中心功能通过NacosDiscoveryClient继承DiscoveryClient,在springcloud中,与Eureka可以无侵入的切换。注册中心可以手动剔除服务实例,通过消息通知客户端更新缓存的实例信息,完整调用链路示例如下:Nacos的关键特性包括:服务发现和服务健康监测动......
  • Docker 部署Nacos
    1、创建Nacos目录mkdir/home/docker/nacos2、创建Nacos日志目录mkdir/home/docker/nacos/logs3、创建Nacos配置目录mkdir/home/docker/nacos/conf4、创建数据库/**Copyright1999-2018AlibabaGroupHoldingLtd.**LicensedundertheApacheLicense,Ver......
  • nacos2.3.2部署(鲲鹏arm版)
    1.说明  本次编译是因为公司适配鲲鹏arm系列,业务涉及到了nacos-server,所以就选择最新版本进行了编译,期间也想直接使用官方镜像nacos/nacos-server:v2.1.2-slim、nacos/nacos-server:v2.2.0-slim,无一例外失败了,启动不了,所以最后只能选择源码编译,在制作镜像的方式进行。2.编......
  • Nacos热更新静态变量配置
    Nacos热更新静态变量配置Springboot项目接入nacos,配置文件统一管理,但静态常量无法通过@Value注解实时热更新(如下所示)。GlobalVariables.java@ComponentpublicclassGlobalVariables{//测试热加载配置字段publicstaticStringtestInfo;@Value("${test......
  • 运维-微服务组件nacos(未写完)
    一、基础概念1.Nacos的概念Nacos/nɑ:kəʊs/是DynamicNamingandConfigurationService的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。Nacos致力于帮助您发现、配置和管理微服务。Nacos提供了一组简单易用的特性集,帮助您快速实现动态......
  • Nacos2.2.0适配瀚高数据库,打镜像部署
    一、Nacos2.2.0适配瀚高数据库Nacos2.2.0适配瀚高数据库部分参考地址:https://blog.csdn.net/weixin_39676699/article/details/130642890application.properties配置文件中数据库部分配置如下:spring.sql.init.platform=highgodb.num=1db.url.0=jdbc:highgo://192.168.1.1:58......
  • 可持久化线段树
    经典的数据结构。权值线段树:维护一个序列,然后记下每个\(a_i\)的出现次数,相当于线段树维护桶。然后这样就可以轻而易举的求出\(1-n\)之间的第\(k\)小数了。原理类似于平衡数求\(rank.\)动态·可持久化下面考虑动态的权值线段树。\(l-r\)查询可以理解为第\(r\)个......