Nacos配置中心组件学习

发布于:2024-08-22 ⋅ 阅读:(108) ⋅ 点赞:(0)

1. Nacos简介

1.1 Nacos是啥

​ Nacos(Dynamic Naming and Configuration Service)是一个开源的服务发现和配置管理平台,主要用于微服务架构中。Nacos的名字源自于“Naming and Configuration Service”的缩写,它提供了两大核心功能:服务发现和服务配置。上篇博文Naocos注册中心。下面我们一起来学习有关Nacos另外一个重要特性Nacos配置中心

1.2 作用
  1. 服务发现
    • 允许服务之间相互发现和通信,支持基于DNS和基于RPC的服务发现。
    • 服务提供者在启动时注册自己,服务消费者通过服务名查找服务,实现服务之间的解耦。
  2. 服务配置
    • 动态配置服务是Nacos的另一个重要功能,允许在所有环境中以集中和动态的方式管理所有服务的配置。
    • 配置的更改可以自动推送到使用该配置的服务,实现配置的热更新,无需重启服务。
  3. 集中管理
    • 提供一个中央配置管理服务来统一管理所有服务的配置,避免了配置文件分散在各个项目里导致的不便维护问题。
  4. 动态更新
    • 能够在不重启服务的情况下,动态地更新配置,提高了系统的灵活性和可维护性。
  5. 版本控制&
    • 配置的变更被版本化,以便追踪变更历史和回滚到之前的配置,增强了配置的管理能力。
  6. 权限控制
    • 对配置的访问进行权限控制,确保只有授权的用户可以修改配置,提高了配置的安全性。
  7. 高可用性和故障转移
    • Nacos服务具有高可用性,能够在部分故障的情况下继续工作,并且能够从故障中恢复,保证了系统的稳定运行。
  8. 多环境配置
    • 支持多环境配置,如开发、测试和生产环境,可以实现环境隔离和配置加密,确保配置的正确性和安全性。
  9. 简化服务治理
    • Nacos无缝支持一些主流的开源生态,如Kubernetes Service、gRPC&Dubbo RPC Service、Spring Cloud RESTful Service等,使得服务治理更加容易和高效。

2. springCloud项目集成

前期准备:部署nacos服务,参考:Naocos注册中心

2.1 maven依赖
<dependency>
     <groupId>com.alibaba.cloud</groupId>
     <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
2.2 Nacos配置相关参数

通常使用bootstrap.propertiesbootstrap.yml文件来配置Nacos的相关参数

spring:
  application:
    name: order-server
   cloud:
    nacos:
      #nacos配置中心配置信息
      config:
        prefix: customer-server
        namespace: nacos-xiu-dev
        server-addr: 127.0.0.0:8848
        file-extension: yml
        # username: name
        # password: pwd!
        
      #nacos服务中心配置  
      discovery:
        server-addr: 127.0.0.0:8848
        namespace: nacos-xiu-dev
        # username: name
        # password: pwd!

在 Nacos Spring Cloud 中,dataId 的完整格式如下:

${prefix}-${spring.profiles.active}.${file-extension}
  • prefix 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。
  • spring.profiles.active 即为当前环境对应的 profile,注意:当 spring.profiles.active 为空时,对应的连接符 - 也将不存在,dataId 的拼接格式变成 ${prefix}.${file-extension}
  • file-exetension 为配置内容的数据格式,可以通过配置项 spring.cloud.nacos.config.file-extension 来配置。目前只支持 propertiesyaml 类型。

按照上述逻辑我们环境为dev在nacos服务里的文件为 命名空间:nacos-xiu-dev文件名称: customer-server-dev.yml

2.3 配置信息

​ 在nacos服务上添加配置信息如下:

nacos: 
  olympic:
   games:
     pingpangball: 马龙,樊振东,孙颖莎
     dive: 全红婵,陈芋汐
     shoot: 黄雨婷,盛李豪 

在这里插入图片描述

配置项 说明 使用场景
命名空间(Namespace) 用于进行不同环境的配置隔离,如开发环境、测试环境和生产环境等。
不同的命名空间下,可以存在相同名称的配置分组(Group)或配置集(Data ID)。
1.隔离不同环境的配置,防止环境间的配置相互干扰。
2.支持多租户配置隔离,不同租户可以使用相同的Nacos集群,但通过命名空间进行隔离
配置分组(Group) 用于对配置集进行分组,不同的配置分组下可以有相同的配置集(Data ID)。 根据功能模块或组件进行配置分组,以便于管理。
配置集
(Data ID)
一个配置文件就是一个配置集,包含了系统各个方面的配置信息。配置集通过Data ID来唯一标识。 配置文件,最细粒度的配置信息,开发最长接触的
多格式支持 Nacos支持多种文件格式的配置项,包括JSON、XML、YAML、Properties、Text等。 常用的为 yaml文件、properties文件
2.5 配置使用

在你的Spring Boot应用中,你可以通过@Value注解或@ConfigurationProperties来注入这些配置。

@Value注入配置

  @Value("${nacos.olympic.games.pingpangball}")
  private String pingpangBall;

  @GetMapping("/getOlympicName")
  public String test() {
     log.info("pingpangBall:{}",pingpangBall);
     return "伦敦奥运会";
  }

@ConfigurationProperties注入配置

//注意必须要有set/get方法
@Data
@Component
//设置配置信息前缀
@ConfigurationProperties(prefix = "nacos.olympic.games")
public class OlympicConfig implements Serializable {
    /**
     * 乒乓球
     */
     private String pingpangBall;
    /**
     * 跳水
     */
    private String dive;
    /**
     * 射击
     */
    private String shoot;
}

使用

@Resource
private OlympicConfig olympicConfig;

@GetMapping("/getOlympicName")
public String test() {
   log.info("config:{}", JsonUtil.toJson(olympicConfig));
   return "伦敦奥运会";
}
2.6 获取实时配置
  1. 启用配置刷新

    • application.ymlapplication.properties文件中添加配置,启用Nacos配置的刷新功能。例如,在application.properties中添加spring.cloud.nacos.config.refresh.enabled=true。默认配置刷新已启用
  2. 使用@RefreshScope注解

    • 在需要实时刷新配置的Bean上添加@RefreshScope注解。这个注解会告诉Spring Cloud在配置发生变化时,重新创建这个Bean,并注入最新的配置信息。
    @Data
    @Component
    @ConfigurationProperties(prefix = "nacos.olympic.games")
    //启用实时刷新
    @RefreshScope
    public class OlympicConfig implements Serializable {
        /**
         * 乒乓球
         */
         private String pingpangBall;
        /**
         * 跳水
         */
        private String dive;
        /**
         * 射击
         */
        private String shoot;
    }
    

Nacos实时刷新的原理

Nacos实时刷新的原理主要依赖于客户端与Nacos服务器之间的长轮询机制。当Nacos客户端启动时,它会向Nacos服务器发起请求,订阅自己关心的配置信息。Nacos服务器会保持这个连接,并在配置信息发生变化时,主动将最新的配置信息推送给客户端。客户端在接收到新的配置信息后,会更新本地缓存,并通知应用程序使用最新的配置。

@RefreshScope 注解的工作原理

作用在类上 作用在方法上
当@RefreshScope 注解被应用在一个类上时,Spring Cloud会为这个类创建一个代理Bean。这个代理Bean会在每次被调用时检查配置是否已更改。如果配置已更改,则Spring Cloud会重新创建实际的Bean实例,并将其注入到应用程序中。 被用在方法上(尽管在实际应用中这种用法并不常见)。然而,需要注意的是,当@RefreshScope 作用在方法上时,它可能并不会像作用在类上时那样直接重新创建Bean实例,而是可能影响到方法调用时的某些行为或结果。但具体的行为可能会根据Spring Cloud的版本和配置而有所不同。

3. nacos自动装配

​ 查看spring-cloud-starter-alibaba-nacos-config maven依赖中的spring.factories中的自动装配类(如下配置类中去掉了重复的配置)

自动装配类 创建的bean实例 bean实例的作用
NacosConfigBootstrapConfiguration NacosConfigProperties 用于封装Nacos配置中心的配置信息,如服务器地址、命名空间、组名等。
加载方式:通过@ConfigurationProperties注解从spring.cloud.nacos.config路径下的配置文件中读取配置项。
NacosConfigManager 作为Nacos配置中心的顶层接口ConfigService的封装,提供配置获取、监听等功能。
NacosPropertySourceLocator 负责从Nacos配置中心加载配置信息,并将这些配置信息封装成PropertySource对象,进而添加到Spring的Environment中,供应用程序使用
NacosConfigAutoConfiguration NacosRefreshProperties 控制Nacos配置中心的配置刷新行为,包括是否启用自动刷新、刷新策略的配置
NacosRefreshHistory 它负责记录并存储配置刷新的历史信息。通过提供详细的历史记录查询功能
NacosContextRefresher nacosContextRefresher类在Nacos配置中心中起到了桥梁和纽带的作用,它通过监听配置变化、触发刷新操作以及发布刷新事件等方式,实现了配置的动态更新和应用程序的灵活调整。
NacosConfigEndpointAutoConfiguration NacosConfigEndpoint NacosConfigEndpoint类通过提供Actuator端点、配置信息查看、动态刷新支持等功能,为Spring Cloud Alibaba项目中的Nacos配置中心提供了丰富的监控和管理手段
NacosConfigHealthIndicator 它主要用于监测Nacos配置中心的健康状态
NacosConnectionFailureAnalyzer nacos客户端(应用程序)连接nacos服务端失败信息的分析(日志打印)
3.1 配置加载原理

从上面的配置可以知道,nacos配置中心中配置加载的入口是

  • 应用启动时,Spring Cloud Alibaba通过BootstrapApplicationContext来加载外部配置。在这个过程中,NacosPropertySourceLocator会被触发,从Nacos Server拉取配置
  • NacosPropertySourceLocator通过ConfigServiceProxy与Nacos Server进行通信,获取配置信息,并将这些信息封装成PropertySource对象,然后添加到Spring的Environment中。
  • 接下来我们就可以像在spring中使用普通配置方式一样了。比如@Value注解或@ConfigurationProperties来注入这些配置。

下面我们来看一看NacosPropertySourceLocator具体实现。

locate方法

locate方法是在Spring Cloud Alibaba的Nacos配置管理中使用的,用于将Nacos中的配置加载到Spring环境中

@Override
public PropertySource<?> locate(Environment env) {
  //设置环境变量(方便后续使用不同的环境(profiles)加载配置)
  nacosConfigProperties.setEnvironment(env);
  //基于nacos配置信息 通过nacosConfigManager获取ConfigService实例,这是与Nacos服务器进行交互的关键组件
  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);
  
  //获取配置的dataId的前缀 正确地定位到Nacos中的配置。
  //一般为:`prefix` 默认为 `spring.application.name` 的值,也可以通过配置项 `spring.cloud.nacos.config.prefix`来配置
  String name = nacosConfigProperties.getName();
  String dataIdPrefix = nacosConfigProperties.getPrefix();
  if (StringUtils.isEmpty(dataIdPrefix)) {
    dataIdPrefix = name;
  }

  if (StringUtils.isEmpty(dataIdPrefix)) {
    dataIdPrefix = env.getProperty("spring.application.name");
  }

  //创建CompositePropertySource 这个对象将用于存储从Nacos加载的所有配置属性源。
  CompositePropertySource composite = new CompositePropertySource(
      NACOS_PROPERTY_SOURCE_NAME);

  //加载共享配置 其配置信息跨多个应用或服务的通用配置。
  //spring.cloud.nacos.config.shared-configs 指定
  loadSharedConfiguration(composite);
  //加载扩展配置 其配置信息包含一些特定于某个服务或功能的配置
  loadExtConfiguration(composite);
  //加载应用配置 常见的配置信息
  loadApplicationConfiguration(composite, dataIdPrefix, nacosConfigProperties, env);
  //返回加载完成后的配置对象
  return composite;
}

共享配置、扩展配置

在这里插入图片描述

加载配置信息

其实不管是loadSharedConfiguration、loadExtConfiguration、loadApplicationConfiguration最终都是调用loadNacosDataIfPresent方法加载配置。这里我们以最常见的设置配置的方式loadApplicationConfiguration方法进行分析。

//加载常用配置
private void loadApplicationConfiguration(
       CompositePropertySource compositePropertySource, String dataIdPrefix,
       NacosConfigProperties properties, Environment environment) {
    //获取配置文件的文件类型 比如yaml、properties等 用于读取到数据的格式化
    String fileExtension = properties.getFileExtension();
    //获取配置分组
    String nacosGroup = properties.getGroup();
  
    //加载默认配置文件 dataId= dataIdPrefix
    
    loadNacosDataIfPresent(compositePropertySource, dataIdPrefix, nacosGroup,
          fileExtension, true);
    // load with suffix, which have a higher priority than the default
    //加载默认配置文件 dataId= dataIdPrefix
    loadNacosDataIfPresent(compositePropertySource,
          dataIdPrefix + DOT + fileExtension, nacosGroup, fileExtension, true);
    // Loaded with profile, which have a higher priority than the suffix
    for (String profile : environment.getActiveProfiles()) {
       String dataId = dataIdPrefix + SEP1 + profile + DOT + fileExtension;
       loadNacosDataIfPresent(compositePropertySource, dataId, nacosGroup,
             fileExtension, true);
    }

dataIdPrefix: 默认为 spring.application.name 的值,也可以通过配置项 spring.cloud.nacos.config.prefix来配置。

以上述的示例代码为例子:spring.application.name=customer-server,profiles=dev

上述代码加载三种类型的配置信息(dataId) customer-server、customer-server.yaml、customer-server-dev.yaml,配置优先级从高到低

为customer-server-dev.yaml —> customer-server.yaml —> customer-server.

具体加载实现

1. loadNacosDataIfPresent方法核心实现
 //加载配置为NacosPropertySource(包含配置信息)
 NacosPropertySource propertySource = this.loadNacosPropertySource(dataId, group,
      fileExtension, isRefreshable);
 //放入composite的配置列表的头部 这表明后加载的配置文件优先级更高
 this.addFirstPropertySource(composite, propertySource, false);

2.loadNacosPropertySource方法核心实现
	NacosPropertySource build(String dataId, String group, String fileExtension,
			boolean isRefreshable) {
    //从nacos服务端加载配置
		Map<String, Object> p = loadNacosData(dataId, group, fileExtension);
    //将配置构造成NacosPropertySource
		NacosPropertySource nacosPropertySource = new NacosPropertySource(group, dataId,
				p, new Date(), isRefreshable);
    //存储到map中
		NacosPropertySourceRepository.collectNacosPropertySource(nacosPropertySource);
		return nacosPropertySource;
	}

3. loadNacosData核心实现
  private Map<String, Object> loadNacosData(String dataId, String group,String fileExtension) {
		String data = null;
		try {
      //从nacos服务端获取配置信息(字符串形式)
			data = configService.getConfig(dataId, group, timeout);
		  //省略日志打印
      //根据配置文件类型将字符串类型的配置信息转换成map
			Map<String, Object> dataMap = NacosDataParserHandler.getInstance()
					.parseNacosData(data, fileExtension);
			return dataMap == null ? EMPTY_MAP : dataMap;
		}
		catch (NacosException e) {
		   //省略异常处理
		}
		return EMPTY_MAP;
	}

3.2 配置实时刷新原理

Nacos 服务器端负责存储配置数据,并提供配置监听和推送的功能。该功能是nacos实时刷新得以实现的基础。

  • 长轮询支持:Nacos 服务器端支持客户端的长轮询请求,即客户端发起一个请求后,服务器会保持这个连接打开,直到有配置更新或超时。这种方式可以减少无效的轮询请求,提高性能。
  • 数据变更通知:当配置数据发生变化时,Nacos 服务器端会记录这些变化,并通知所有正在等待的客户端。这通常通过维护一个客户端连接列表,并在数据变化时遍历这个列表来实现。
  • nacos与spring cloud整合,nacos基于spring的事件发布和监听机制,会在spring启动后注册一个配置变化的事件监听。其启作用的为NacosContextRefresher

NacosContextRefresher

spring启动时候注册配置变更事件

@Override
public void onApplicationEvent(ApplicationReadyEvent event) {
    // many Spring context
    if (this.ready.compareAndSet(false, true)) {
       //注册nacos配置变更事件
       this.registerNacosListenersForApplications();
    }
}
private void registerNacosListenersForApplications() {
    //是否开启自动刷新 默认为true
    if (isRefreshEnabled()) {
       //针对需要加载的所有配置文件都分别进行事件监听
       for (NacosPropertySource propertySource : NacosPropertySourceRepository
             .getAll()) {
          if (!propertySource.isRefreshable()) {
             continue;
          }
          //以上面示例代码为例 分别对customer-server、customer-server.yaml、customer-server-dev.yaml、
          String dataId = propertySource.getDataId();
          //添加事件监听
          registerNacosListener(propertySource.getGroup(), dataId);
       }
    }
}
private void registerNacosListener(final String groupKey, final String dataKey) {
    String key = NacosPropertySourceRepository.getMapKey(dataKey, groupKey);
  
    //创建监听配置变化的监听器,其方法innerReceive即为配置变更处发的逻辑
    Listener listener = listenerMap.computeIfAbsent(key,
          lst -> new AbstractSharedListener() {
             @Override
             public void innerReceive(String dataId, String group,
                   String configInfo) {
                refreshCountIncrement();
                nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo);
                // todo feature: support single refresh for listening
                applicationContext.publishEvent(
                      new RefreshEvent(this, null, "Refresh Nacos config"));
                if (log.isDebugEnabled()) {
                   log.debug(String.format(
                         "Refresh Nacos config group=%s,dataId=%s,configInfo=%s",
                         group, dataId, configInfo));
                }
             }
          });
    try {
       //为nacos服务添加事件监听器
       configService.addListener(dataKey, groupKey, listener);
    }
    catch (NacosException e) {
       log.warn(String.format(
             "register fail for nacos listener ,dataId=[%s],group=[%s]", dataKey,
             groupKey), e);
    }
}

这段代码展示了如何在Spring Cloud Alibaba的Nacos配置中心中注册一个监听器,以便在配置发生变化时能够接收到通知并执行相应的更新逻辑

  • 构建配置变更事件监听器
  • 为nacos服务添加事件监听器

innerReceive方法

该方法三个参数, 当某个分组group下的某个配置dataId发生变化则会将最新的配置信息configInfo传递到该方法中

  public void innerReceive(String dataId, String group,
                   String configInfo) {
      //累加配置变更次数
      refreshCountIncrement();
      //记录此次变化到历史中,便于追溯历史变更记录
      nacosRefreshHistory.addRefreshRecord(dataId, group, configInfo);
      //发布一个刷新事件,接受到该事件的组件即可获取到最新配置 
      //比如@RefreshScope底层逻辑肯定是消费了该RefreshEvent事件 从而获取到最新变化配置
      applicationContext.publishEvent(
            new RefreshEvent(this, null, "Refresh Nacos config"));
      if (log.isDebugEnabled()) {
         log.debug(String.format(
               "Refresh Nacos config group=%s,dataId=%s,configInfo=%s",
               group, dataId, configInfo));
      }
   }

4. nacos配置中心原理

Nacos配置中心的工作原理主要围绕动态配置管理、配置存储与一致性、长轮询与推送机制以及本地缓存与版本控制等核心原理展开。以下是详细的工作原理介绍:

3.1. 动态配置管理
  • 功能概述:Nacos配置中心提供了一种集中式的动态配置管理功能,允许开发者实现配置的集中管理、动态更新和实时推送。这意味着当配置信息发生变化时,Nacos能够自动将更新推送给所有相关的服务实例,无需重启服务即可使新配置生效。
  • 技术实现:Nacos通过集中存储配置信息(如使用MySQL等数据库)来确保配置数据的安全性和持久性。同时,它支持多种配置格式(如Properties、YAML等),以满足不同应用场景下的配置需求。
3.2. 配置存储与一致性
  • 配置存储:Nacos采用集中式的存储方式,将配置信息存储在可靠的存储介质中。这种集中存储方式使得配置信息的管理更加便捷和统一。
  • 一致性保证:在集群部署模式下,Nacos通过一致性协议(如Raft协议)来保证配置数据在不同节点之间的一致性。即使在部分节点发生故障的情况下,也能保证配置数据的完整性和准确性。

3.3. 长轮询与推送机制

  • 长轮询机制:Nacos客户端通过长轮询机制与服务器保持连接,以实时获取配置更新。当配置发生变化时,服务器会主动将更新推送给客户端,而不是让客户端定时轮询查询。这种推送机制大大减少了客户端与服务器之间的通信次数,提高了配置更新的实时性和效率。
  • 推送机制:推送可以通过HTTP长轮询或WebSocket等方式实现。使用WebSocket可以更加实时地推送配置变更,但需要确保网络环境支持WebSocket。
3.4. 本地缓存与版本控制
  • 本地缓存:为了提高性能并减少对服务器的访问压力,Nacos客户端会将获取到的配置信息缓存在本地。当本地缓存中的配置信息与服务器上的配置信息不一致时,客户端会重新从服务器拉取最新的配置信息。
  • 版本控制:Nacos为每个配置项分配一个唯一的版本号。当配置发生变化时,版本号也会随之更新。客户端在发起请求时可以携带自己的配置版本号,以便服务器判断是否需要推送新的配置信息给客户端。
3.5. 安全性与权限管理
  • 安全性:Nacos提供了多种安全措施来保护配置信息的安全性,如数据加密、访问控制等。
  • 权限管理:Nacos实现了权限管理功能,允许管理员在控制台创建不同的账户,并分配不同的权限(如读写、只读)。这样可以确保只有具有相应权限的用户才能访问或修改配置信息。

网站公告

今日签到

点亮在社区的每一天
去签到