热门标签 | 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 返回是为了最大程度上保证客户端不会因为网络延时造成超时。

 



推荐阅读
  • H5技术实现经典游戏《贪吃蛇》
    本文将分享一个使用HTML5技术实现的经典小游戏——《贪吃蛇》。通过H5技术,我们将探讨如何构建这款游戏的两种主要玩法:积分闯关和无尽模式。 ... [详细]
  • 本文介绍了SIP(Session Initiation Protocol,会话发起协议)的基本概念、功能、消息格式及其实现机制。SIP是一种在IP网络上用于建立、管理和终止多媒体通信会话的应用层协议。 ... [详细]
  • 本文是对《敏捷软件开发:原则、模式与实践》一书的深度解析,书中不仅探讨了敏捷方法的核心理念及其应用,还详细介绍了面向对象设计的原则、设计模式的应用技巧及UML的有效使用。 ... [详细]
  • Docker安全策略与管理
    本文探讨了Docker的安全挑战、核心安全特性及其管理策略,旨在帮助读者深入理解Docker安全机制,并提供实用的安全管理建议。 ... [详细]
  • 本文详细介绍了如何在Oracle VM VirtualBox中实现主机与虚拟机之间的数据交换,包括安装Guest Additions增强功能,以及如何利用这些功能进行文件传输、屏幕调整等操作。 ... [详细]
  • Beetl是一款先进的Java模板引擎,以其丰富的功能、直观的语法、卓越的性能和易于维护的特点著称。它不仅适用于高响应需求的大型网站,也适合功能复杂的CMS管理系统,提供了一种全新的模板开发体验。 ... [详细]
  • 本文详细介绍了在Windows系统中如何配置Nginx以实现高效的缓存加速功能,包括关键的配置文件设置和示例代码。 ... [详细]
  • 我的读书清单(持续更新)201705311.《一千零一夜》2006(四五年级)2.《中华上下五千年》2008(初一)3.《鲁滨孙漂流记》2008(初二)4.《钢铁是怎样炼成的》20 ... [详细]
  • 本文档介绍了如何使用OpenStack命令行工具在Keystone身份服务中创建和管理域、项目、用户及角色。随着Keystone命令向OpenStack命令集的迁移,了解这些新的命令格式对于系统管理员来说至关重要。 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 本文将从基础概念入手,详细探讨SpringMVC框架中DispatcherServlet如何通过HandlerMapping进行请求分发,以及其背后的源码实现细节。 ... [详细]
  • 本文探讨了在一个物理隔离的环境中构建数据交换平台所面临的挑战,包括但不限于数据加密、传输监控及确保文件交换的安全性和可靠性。同时,作者结合自身项目经验,分享了项目规划、实施过程中的关键决策及其背后的思考。 ... [详细]
  • 本文详细介绍了在Linux操作系统上安装和部署MySQL数据库的过程,包括必要的环境准备、安装步骤、配置优化及安全设置等内容。 ... [详细]
  • 本文详细介绍了如何利用 Bootstrap Table 实现数据展示与操作,包括数据加载、表格配置及前后端交互等关键步骤。 ... [详细]
  • 如何在PHP中安装Xdebug扩展
    本文介绍了如何从PECL下载并编译安装Xdebug扩展,以及如何配置PHP和PHPStorm以启用调试功能。 ... [详细]
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社区 版权所有