NacosConfig

本文介绍了配置中心在微服务架构中的重要性,对比了NacosConfig和SpringCloudConfig的工作原理,以及Apollo的特点。重点阐述了Nacos的简单架构、配置文件加载和动态更新机制,以及避免羊群效应和自动感知配置更新的方法。
摘要由CSDN通过智能技术生成

1.1、配置中心功能

集群中每一台主机的配置文件都是相同的,对配置文件的更新维护就成为了一个棘手的

问题,Nacos 是可以对 Spring Cloud 中各个微服务配置文件进行统一维护管理的配置中心。

1.2、常见配置中心工作原理

1.2.1 Spring Cloud Config

1.2.2 Nacos Config

(1) 系统架构

(2)数据模型

Namespace、Group、Service、DataId,DataId是配置文件的名称

在后面阅读 Nacos Config 源码过程中会看到一个概念:tenant。中文意思是租户,房客。 其实,tenant 就是 namespace,是 bootstrap.yml 文件属性 spring.cloud.nacos.config 中指定的 namespace。在代码中为了区分 spring.cloud.nacos.discovery 中指定的 namespace,所以起了 tenant 这个名字。

1.2.3 Apollo

Apollo 是由携程推出的一款开源的分布式配置中心。

(1) 系统架构

(2)工作原理

1.2.4 对比

1)、 系统架构复杂度:

Nacos Config 最为简单,无需消息总线系统,无需 Eureka 等。而 Apollo 与 Spring Cloud Config 系统搭建成本及复杂度较 Nacos 要高很多。

2)、羊群效应:

对于 Spring Cloud Config,Config Client 需要提交配置更新请求。当微服务系 统很庞大时,任何一个 Config Client 的更新请求的提交,都会引发所有“Bus 在线 Config Client“的配置更新请求的提交,即会引发羊群效应。这将会导致 Config Client 的效率下 降,导致整个系统的效率下降。而 Nacos Config 与 Apollo 则是“定点更新”,谁的配置 更新了向谁推送。

3)、自动感知配置更新:

Spring Cloud Config 是 Config Client 不提交请求,其是无法感知配置 更新的。但 Nacos 与 Apollo 则是,当 Config Server 中的配置文件发生了变更,Config Client 会自动感知到这个变更,无需 Config Client 端的用户做任何操作。

4)、配置文件类型:

Nacos Config 与 Spring Cloud Config 配置文件支持比较多的类型,支持 yaml、text、json、xml、html、Properties 等,但 Apollo 只支持 xml、text、Properties 类 型,不支持 yaml

依赖

<dependencies>
        <!--nacos discovery依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>

        <!--nacos config依赖-->
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
        </dependency>

        <!--actuator依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-actuator</artifactId>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>

        <!--修改MySQL驱动版本-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.47</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
    </dependencies>

1.3、配置文件的加载

Nacos Config Client 在启动时是如何将远程配置中心 Nacos Config Server 中的配置文件加

载到本地的呢?这里要解决这个问题。

1.3.1 源码基础

(1) 基本配置说明
spring:
  application:
  	#根据微服务名称来找动态配置文件
    name: abcmsc-provider-depart
  cloud:
    nacos:
      config:
        server-addr: localhost:8848
      	#指定配置文件为yml类型
        file-extension: yml

        # 共享配置:要求共享配置文件与应用必须在同一个group中
        shared-configs: aaa.yml, bbb.yml
  #        shared-configs[0]:
  #          data-id: aaa.yml
  #          refresh: true
  #        shared-configs[1]:
  #          data-id: bbb.yml
  #          refresh: true

        # 扩展配置:当前应用与扩展配置文件无须在同一个group
        extension-configs: ccc.yml, ddd.yml
#        extension-configs[0]:
#          data-id: ccc.yml
#          group: other
#          refresh: true
#        extension-configs[1]:
#          data-id: ddd.yml
#          group: other
#          refresh: true

	#多环境选择
  profiles:
    active: test

   # abcmsc-provider-depart-test.yml

nacos config client 要加载的配置文件有三种:

  • 自身配置文件
  • 共享配置文件
  • 扩展配置文件
(2)共享配置说明

(3)扩展配置说明

(4)加载顺序说明

以上三类配置文件的加载顺序为,共享配置 -> 扩展配置 -> 当前应用自身配置,如果

存在相同属性配置了不同属性值,则后加载的会将先加载的给覆盖。即优先级为:共享配置

< 扩展配置 < 应用自身配置。

对于每种配置文件的加载过程,又存在三种可用选择:在应用本地存在同名配置,远程

配置中心存在同名配置,本地磁盘快照 snapshot 中存在同名配置。这三种配置的优先级为:

本地配置 > 远程配置 > 快照配置。只要前面的加载到了,后面的就不再加载。

若要在应用本地存放同名配置,则需要存放到当前用户主目录下的

nacos\config\fixed-localhost_8848_nacos\data\config-data\{groupId}目录中。

若开启了配置的快照功能,则默认会将快照记录在当前用户主目录下的

nacos\config\fixed-localhost_8848_nacos\snapshot\{groupId}目录中。

(5)、源码跟踪:Nacos Config Client配置文件的加载
// SpringBoot在启动时会准备环境,此时会调用该方法。
// 该方法会从配置中心加载配置文件
@Override
    public PropertySource<?> locate(Environment env) {
    // 将bootstrap.yml文件内容加载到内存
    nacosConfigProperties.setEnvironment(env);
ConfigService configService = nacosConfigManager.getConfigService();

if (null == configService) {
    log.warn("no instance of config service found, can't load config from nacos");
    return null;
}
// 配置文件加载超时时限
long timeout = nacosConfigProperties.getTimeout();
nacosPropertySourceBuilder = new NacosPropertySourceBuilder(configService,
                                                            timeout);
// 获取spring.cloud.nacos.config.name属性值,即要加载的配置文件的名称
String name = nacosConfigProperties.getName();

// 获取spring.cloud.nacos.config.prefix属性值,即要加载的配置文件的名称
String dataIdPrefix = nacosConfigProperties.getPrefix();
if (StringUtils.isEmpty(dataIdPrefix)) {
    dataIdPrefix = name;
}

// 若没有设置name与prefix属性,则要加载的配置文件名称取spring.application.name属性值
if (StringUtils.isEmpty(dataIdPrefix)) {
    dataIdPrefix = env.getProperty("spring.application.name");
}

CompositePropertySource composite = new CompositePropertySource(
    NACOS_PROPERTY_SOURCE_NAME);

// 加载共享配置
// 1)首先加载本地配置
// 2)若没有,则加载远程配置
// 3)若没有,则加载本地快照配置
loadSharedConfiguration(composite);
// 加载扩展配置
loadExtConfiguration(composite);
// 加载自身配置(注意,其会加载三类配置文件)
// 关于配置文件中的“三类”共有三种,要注意
loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
return composite;
}

1.4、配置文件的动态更新

当远程 Nacos Config Server 中的配置信息发生了变更,Nacos Config Client 是如何感知到

的呢?这里就来解决这个问题。

1.4.1 长轮询模型

Nacos Config Server 中配置数据的变更,Nacos Config Client 是如何知道的呢?Nacos

Config Server 采用了长轮询模型实现的变更通知。

一般情况下 Server 端数据的变更若要使 Client 感知到,可以选择两种模型:

 Push 模型:当 Server 端的数据发生了变更,其会主动将更新推送给 Client。Push 模型

适合于 Client 数量不多,且 Server 端数据变化比较频繁的场景。其实时性较好,但其需

要维护长连接,占用系统资源。

 Pull 模型:需要 Client 定时查看 Server 端数据是否更新。其实时性不好,且可能会产生

数据更新的丢失。

长轮询模型整合了 Push 与 Pull 模型的优势。Client 仍定时发起 Pull 请求,查看 Server

端数据是否更新。若发生了更新,则 Server 立即将更新数据以响应的形式发送给 Client 端;

若没有发生更新,Server 端不会发送任何信息,但其会临时性的保持住这个连接一段时间。

若在此时间段内,Server 端数据发生了变更,这个变更就会触发 Server 向 Client 发送变更结

果。这次发送的执行,就是因为长连接的存在。若此期间仍未发生变更,则放弃这个连接。

等待着下一次 Client 的 Pull 请求。

长轮询模型,是 Push 与 Pull 模型的整合,既减少了 Push 模型中长连接的被长时间维护

的时间,又降低了 Pull 模型实时性较差的问题。

1.4.2、 config client 定时发出更新检测

NacosConfigService -> ClientWorker –> 启动一个定时任务

cacheMap CacheData

1.4.3 、config client 将更新同步到应用实例

要解决的问题有两个:

1) config client 的每个配置文件对应的 cacheData 是什么时候创建的?

2) 如何将更新过的 cacheData 中的数据同步到应用实例的?

总思路:

在 config client 启动时会为每个其所需要的配置文件创建一个本地缓存 CacheData,并为

每个 CacheData 添加一个监听器。一旦监听到 CacheData 中数据发生了变更,就会引发监听

回调的执行。该回调并未直接从 CacheData 中读取变更数据,而是发布了一个刷新事件

RefreshEvent。该事件能够触发所有被@RefreshScope 注解的类实例被重新创建并初始化,而

初始化时使用的会自动更新的属性(被@Value 注解的属性)值就来自于 CacheData。

1.4.4 、config server 处理 client 配置变更检测请求

总思路:

当 config server 接收到 config client 的配置变更检测请求后,首先会解析出请求指定的

要检测的所有目标配置文件,同时也会解析出 client 对处理方式的要求。server 的处理方式

有四种类型:

 短轮询:没有长连接维护。server 接收到 client 请求后立即轮询检测所有目标配置文件

是否发生变更,并将检测结果立即返回 client。不过,这个返回的结果与 nacos client 的

版本有密切关系,版本不同形成的结果不同。

 固定时长的长轮询:server 接收到 client 请求后,会直接维护一个指定的固定时长的长

连接,默认 30s。长连接结束前会检测一次是否发生配置变更。不过,在长连接维护期

间是不检测配置变更情况的。

 不挂起的非固定时长的长轮询:与短轮询类似。server 接收到 client 请求后立即轮询检

测所有目标配置文件是否发生变更,并将检测结果立即返回 client。与短轮询不同的是,

其返回结果与 nacos client 版本无关。

 挂起的非固定时长的长轮询:server 接收到 client 请求后,会先检测是否发生了配置变

更。若发生了,则直接返回 client,关闭连接。若未发生,则首先会将这个长轮询实例

写入到一个缓存队列 allSubs,然后维护一个 30s 的长连接(这个时间用户不能指定)。

时间结束,长连接直接关闭。在该长连接维护期间,系统同时监听着配置变更事件,一

旦发生变更就会立即将变更发送给相应的长轮询对应的 client,关闭连接。

配置文件是否发生变更,是如何判断的?

就是把来自于 client 的配置文件的 md5 与 server 端配置文件的 md5 进行对比。若相等,则

未发生变更,否则,发生了变更。

server 创建的客户端长轮询实例,是为谁创建的?是为每个 config client 都会创建一个长轮

询实例?还是为每个配置文件都创建一个长轮询实例?

都不是。是为每次的配置更新检测请求创建一个长轮询实例。

1.4.5、config server 感知配置变更后通知 client

总思路:

在 Nacos Config Server 启动时会创建 LongPollingService 实例,而在创建 LongPollingService

实例时,会首先创建一个 allSubs 队列,同时还会注册一个 LocalDataChangeEvent 的订阅者。

一旦 Server 中保存的配置发生变更,就会触发订阅者的回调方法的执行。而回调方法则会

引发 DataChangeTask 的异步任务执行。

DataChangeTask 任务就是从当前 server 所 hold 的所有长轮询实例集合 allSubs 中查找,

这个发生了变更的配置文件是哪个长轮询实例对应的 client 要检测的变更,然后将这个发生

变更的配置文件key发送给这个长轮询对应的client,并将这个长轮询实例从allSubs中删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值