热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

源码解析Nacos配置中心

一、Nacos配置中心实战官方文档:https:github.comalibabaspring-cloud-alibabawikiNacos-config1.1快速开始准备配置,n

一、Nacos配置中心实战

官方文档: https://github.com/alibaba/spring-cloud-alibaba/wiki/Nacos-config


1.1 快速开始

准备配置,nacos server(本地ip:8848/nacos/index.html)中新建nacos-config.properties





Data ID: nacos-config.properties
Group : DEFAULT_GROUP
配置格式: Properties
配置内容: user.name=shiwn
      user.age=100

注意:Data Id是以 properties (默认的文件扩展名方式)为扩展名,名称可自由定义(如:redis-config.properties,mybaties.properties)

 


1.2 搭建nacos-config服务

通过 Nacos Server 和 spring-cloud-starter-alibaba-nacos-config 实现配置的动态变更

  1)引入依赖



com.alibaba.cloud
spring-cloud-starter-alibaba-nacos-config

  2)添加 bootstrap.properties

spring.application.name=nacos-config
# 配置中心地址
spring.cloud.nacos.config.server
-addr=127.0.0.1:8848

   3) 启动服务,测试微服务是否使用配置中心的配置

@SpringBootApplication
public class ServiceNacosConfigApplication {
public static void main(String[] args) {
ConfigurableApplicationContext applicationContext
= SpringApplication.run(ServiceNacosConfigApplication.class, args);
// 当动态配置刷新时,会更新到 Enviroment中,因此这里每隔3秒中从Enviroment中获取配置
while (true) {
String userName
= applicationContext.getEnvironment().getProperty("common.name");
String userAge
= applicationContext.getEnvironment().getProperty("common.age");
System.err.println(
"common name :" + userName + "; age: " + userAge);
try {
TimeUnit.SECONDS.sleep(
3);
}
catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}

启动项目,可以看到如下输出结果:读取了 nacos server 中的配置

 


1.3 Config相关配置


支持配置的动态更新

代码参考1.2-3

Note:你可以通过配置 spring.cloud.nacos.config.refresh.enabled=false 来关闭动态刷新 


支持profile粒度的配置

spring-cloud-starter-alibaba-nacos-config 在加载配置的时候,不仅仅加载了以 dataid 为 ${spring.application.name}.${file-extension:properties} 为前缀的基础配置,还加载了dataid为 ${spring.application.name}-${profile}.${file-extension:properties} 的基础配置。在日常开发中如果遇到多套环境下的不同配置,可以通过Spring 提供的 ${spring.profiles.active} 这个配置项来配置。

spring.profiles.active=develop

Note${spring.profiles.active} 当通过配置文件来指定时必须放在 bootstrap.properties 文件中。


支持自定义 namespace 的配置

用于进行租户粒度的配置隔离。不同的命名空间下,可以存在相同的 Group 或 Data ID 的配置。Namespace 的常用场景之一是不同环境的配置的区分隔离,例如开发测试环境和生产环境的资源(如配置、服务)隔离等。

在没有明确指定 ${spring.cloud.nacos.config.namespace} 配置的情况下, 默认使用的是 Nacos 上 Public 这个namespae。如果需要使用自定义的命名空间,可以通过以下配置来实现:

spring.cloud.nacos.config.namespace=b3404bc0-d7dc-4855-b519-570ed34b62d7

Note该配置必须放在 bootstrap.properties 文件中。此外 spring.cloud.nacos.config.namespace 的值是 namespace 对应的 id,id 值可以在 Nacos 的控制台获取。并且在添加配置时注意不要选择其他的 namespae,否则将会导致读取不到正确的配置。


支持自定义 Group 的配置

在没有明确指定 ${spring.cloud.nacos.config.group} 配置的情况下, 默认使用的是 DEFAULT_GROUP 。如果需要自定义自己的 Group,可以通过以下配置来实现:

spring.cloud.nacos.config.group=DEVELOP_GROUP

Note该配置必须放在 bootstrap.properties 文件中。并且在添加配置时 Group 的值一定要和 spring.cloud.nacos.config.group 的配置值一致。 


支持自定义扩展的 Data Id 配置

通过自定义扩展的 Data Id 配置,既可以解决多个应用间配置共享的问题,又可以支持一个应用有多个配置文件。

# 配置支持共享的 Data Id
spring.cloud.nacos.config.shared
-configs[0].data-id=common.yaml
# 配置 Data Id 所在分组,缺省默认 DEFAULT_GROUP
spring.cloud.nacos.config.shared
-configs[0].group=GROUP_APP1
# 配置Data Id 在配置变更时,是否动态刷新,缺省默认
false
spring.cloud.nacos.config.shared
-configs[0].refresh=true

# 配置支持一个应用多个 DataId 的配置
spring.cloud.nacos.config.extensionConfigs[
0].data-id=ext-config-common01.properties
spring.cloud.nacos.config.extensionConfigs[
0].group=REFRESH_GROUP
spring.cloud.nacos.config.extensionConfigs[
0].refresh=true
spring.cloud.nacos.config.extensionConfigs[
1].data-id=ext-config-common02.properties
spring.cloud.nacos.config.extensionConfigs[
1].group=REFRESH_GROUP

 


1.4 配置的优先级

Spring Cloud Alibaba Nacos Config 目前提供了三种配置能力从 Nacos 拉取相关的配置。



  • A: 通过 spring.cloud.nacos.config.shared-configs[n].data-id 支持多个共享 Data Id 的配置



  • B: 通过 spring.cloud.nacos.config.extension-configs[n].data-id 的方式支持多个扩展 Data Id 的配置



  • C: 通过内部相关规则(应用名、应用名+ Profile )自动生成相关的 Data Id 配置



当三种方式共同使用时,他们的一个优先级关系是:A

优先级从高到低:

  1) nacos-config-product.yaml 精准配置

  2) nacos-config.yaml 同工程不同环境的通用配置

  3) ext-config: 不同工程 扩展配置

  4) shared-dataids 不同工程通用配置

 


1.5 @RefreshScope

@Value注解可以获取到配置中心的值,但是无法动态感知修改后的值,需要利用@RefreshScope注解:

@RestController
@RefreshScope
public class TestController {
@Value(
"${common.age}")
private String age;
@GetMapping(
"/common")
public String hello() {
return age;
}
}

 


二、Nacos配置中心架构剖析

2.1 配置中心的架构

配置中心使用demo

@SpringBootApplication
public class ServiceNacosConfigApplication {
public static void main(String[] args) {
try {
String serverAddr
= "localhost";
String dataId
= "nacos-config-demo.yaml";
String group
= "DEFAULT_GROUP";
Properties properties
= new Properties();
properties.put(PropertyKeyConst.SERVER_ADDR, serverAddr);
//获取配置服务
ConfigService cOnfigService= NacosFactory.createConfigService(properties);
//获取配置
String cOntent= configService.getConfig(dataId, group, 5000);
System.out.println(content);
//注册监听器
configService.addListener(dataId, group, new Listener() {
@Override
public void receiveConfigInfo(String configInfo) {
System.out.println(
"===recieve:" + configInfo);
}
@Override
public Executor getExecutor() {
return null;
}
});
//发布配置
//boolean isPublishOk = configService.publishConfig(dataId, group, "content");
//System.out.println(isPublishOk);
//发送properties格式
configService.publishConfig(dataId, group, "common.age=30", ConfigType.PROPERTIES.getType());
Thread.sleep(
3000);
content
= configService.getConfig(dataId, group, 5000);
System.out.println(content);
}
catch (Exception e) {
}
}
}

在nacos服务端查看发布的配置

 


2.2 nacos config client源码分析

配置中心核心接口ConfigService


2.2.1 获取配置 

  获取配置的主要方法是 NacosConfigService 类的 getConfig 方法,通常情况下该方法直接从本地文件中取得配置的值,如果本地文件不存在或者内容为空,则再通过 HTTP GET 方法从远端拉取配置,并保存到本地快照中。当通过 HTTP 获取远端配置时,Nacos 提供了两种熔断策略,一是超时时间,二是最大重试次数,默认重试三次。

 


2.2.2 注册监听器  

  配置中心客户端会通过对配置项注册监听器达到在配置项变更的时候执行回调的功能。

String getConfigAndSignListener(String dataId, String group, long timeoutMs, Listener listener) throws NacosException;
void addListener(String dataId, String group, Listener listener) throws NacosException;

  Nacos 可以通过以上方式注册监听器,它们内部的实现均是调用 ClientWorker 类的 addCacheDataIfAbsent。其中 CacheData 是一个维护配置项和其下注册的所有监听器的实例,所有的 CacheData 都保存在 ClientWorker 类中的原子 cacheMap 中,其内部的核心成员有:


2.2.3 配置长轮询

  ClientWorker 通过其下的两个线程池完成配置长轮询的工作,一个是单线程的 executor,每隔 10ms 按照每 3000 个配置项为一批次捞取待轮询的 cacheData 实例,将其包装成为一个 LongPollingTask 提交进入第二个线程池 executorService 处理。

 


2.3 nacos config server源码分析


2.3.1 配置dump

  服务端启动时就会依赖 DumpService 的 init 方法,从数据库中 load 配置存储在本地磁盘上,并将一些重要的元信息例如 MD5 值缓存在内存中。服务端会根据心跳文件中保存的最后一次心跳时间,来判断到底是从数据库 dump 全量配置数据还是部分增量配置数据(如果机器上次心跳间隔是 6h 以内的话)。

  全量 dump 当然先清空磁盘缓存,然后根据主键 ID 每次捞取一千条配置刷进磁盘和内存。增量 dump 就是捞取最近六小时的新增配置(包括更新的和删除的),先按照这批数据刷新一遍内存和文件,再根据内存里所有的数据全量去比对一遍数据库,如果有改变的再同步一次,相比于全量 dump 的话会减少一定的数据库 IO 和磁盘 IO 次数。 


2.3.2 配置发布

  发布配置的代码位于 ConfigController#publishConfig中。集群部署,请求一开始也只会打到一台机器,这台机器将配置插入Mysql中进行持久化。服务端并不是针对每次配置查询都去访问 MySQL ,而是会依赖 dump 功能在本地文件中将配置缓存起来。因此当单台机器保存完毕配置之后,需要通知其他机器刷新内存和本地磁盘中的文件内容,因此它会发布一个名为 ConfigDataChangeEvent 的事件,这个事件会通过 HTTP 调用通知所有集群节点(包括自身),触发本地文件和内存的刷新。


2.3.3 处理长轮询

  客户端会有一个长轮询任务,拉取服务端的配置变更,服务端处理逻辑在LongPollingService类中,其中有一个 Runnable 任务名为ClientLongPolling,服务端会将受到的轮询请求包装成一个 ClientLongPolling 任务,该任务持有一个 AsyncContext 响应对象,通过定时线程池延后 29.5s 执行。比客户端 30s 的超时时间提前 500ms 返回是为了最大程度上保证客户端不会因为网络延时造成超时。

 



推荐阅读
  • 深入解析 Apache Shiro 安全框架架构
    本文详细介绍了 Apache Shiro,一个强大且灵活的开源安全框架。Shiro 专注于简化身份验证、授权、会话管理和加密等复杂的安全操作,使开发者能够更轻松地保护应用程序。其核心目标是提供易于使用和理解的API,同时确保高度的安全性和灵活性。 ... [详细]
  • 本文介绍了如何使用 Spring Boot DevTools 实现应用程序在开发过程中自动重启。这一特性显著提高了开发效率,特别是在集成开发环境(IDE)中工作时,能够提供快速的反馈循环。默认情况下,DevTools 会监控类路径上的文件变化,并根据需要触发应用重启。 ... [详细]
  • 本文详细介绍了如何在Linux系统上安装和配置Smokeping,以实现对网络链路质量的实时监控。通过详细的步骤和必要的依赖包安装,确保用户能够顺利完成部署并优化其网络性能监控。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文详细介绍了Java编程语言中的核心概念和常见面试问题,包括集合类、数据结构、线程处理、Java虚拟机(JVM)、HTTP协议以及Git操作等方面的内容。通过深入分析每个主题,帮助读者更好地理解Java的关键特性和最佳实践。 ... [详细]
  • UNP 第9章:主机名与地址转换
    本章探讨了用于在主机名和数值地址之间进行转换的函数,如gethostbyname和gethostbyaddr。此外,还介绍了getservbyname和getservbyport函数,用于在服务器名和端口号之间进行转换。 ... [详细]
  • 本文详细介绍了如何在 Spring Boot 应用中通过 @PropertySource 注解读取非默认配置文件,包括配置文件的创建、映射类的设计以及确保 Spring 容器能够正确加载这些配置的方法。 ... [详细]
  • 本文详细介绍如何使用Samba软件配置CIFS文件共享服务,涵盖安装、配置、权限管理及多用户挂载等关键步骤。通过具体示例和命令行操作,帮助读者快速搭建并优化Samba服务器。 ... [详细]
  • 本文探讨了领域驱动设计(DDD)的核心概念、应用场景及其实现方式,详细介绍了其在企业级软件开发中的优势和挑战。通过对比事务脚本与领域模型,展示了DDD如何提升系统的可维护性和扩展性。 ... [详细]
  • 本文探讨了如何在 PHP 的 Eloquent ORM 中实现数据表之间的关联查询,并通过具体示例详细解释了如何将关联数据嵌入到查询结果中。这不仅提高了数据查询的效率,还简化了代码逻辑。 ... [详细]
  • 本文探讨了 Spring Boot 应用程序在不同配置下支持的最大并发连接数,重点分析了内置服务器(如 Tomcat、Jetty 和 Undertow)的默认设置及其对性能的影响。 ... [详细]
  • 本文详细解释了如何使用@IfProfileValue注解来检测Spring框架中的配置文件是否处于活动状态,并探讨其与@Profile和@activeProfiles的区别。 ... [详细]
  • Struts与Spring框架的集成指南
    本文详细介绍了如何将Struts和Spring两个流行的Java Web开发框架进行整合,涵盖从环境配置到代码实现的具体步骤。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 探讨如何真正掌握Java EE,包括所需技能、工具和实践经验。资深软件教学总监李刚分享了对毕业生简历中常见问题的看法,并提供了详尽的标准。 ... [详细]
author-avatar
手机用户2502863161
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有