分布式配置中心Nacos

(一)本地配置方式的问题

1、配置的动态更新
在实际应用中会有动态更新配置的需求,比如修改服务连接地址、限流的配置等。在传统模式下,需要手动修改配置文件并且重启应用才能生效,这种方式效率太低,重启也会导致服务暂时不可用。

2、配置集中式管理
在微服务架构中,某些核心服务为了保证高性能会部署上百个节点,如果在每个节点中都维护一个配置文件,一旦配置文件中的某个属性需要修改,可想而知,工作量是巨大的。

3、配置内容的安全性和权限
配置文件随着源代码统一提交到代码库中,容易造成生产环境配置信息的数据泄露。

4、不同部署环境下配置的管理
前面提到过通过profile机制来管理不同环境下的配置,这种方式对于日常维护来说比较烦琐。

(二)Nacos配置中心

(1)基本介绍

配置中心的开源解决方案很多,比如ZooKeeper、Disconf、Apollo、Spring Cloud Config、QConf、Nacos等。同样,不管是哪一种解决方案,它的核心功能是不会变的。

Nacos是Alibaba开源的中间件,我们知道在Nacos的架构图中有两个模块,分别是Config Service和Naming Service。其中Config Service就是Nacos用于实现配置中心的核心模块,它实现了对配置的CRUD、版本管理、灰度管理、监听管理、推送轨迹、聚合数据等功能。我们主要围绕Nacos中的Config Service模块实现配置中心的功能进行深度的分析。

(2)基于Data ID配置YAML的文件扩展名

Spring Cloud Alibaba Nacos Config从Nacos Config Server中加载配置时,会匹配Data ID。在SpringCloud Nacos的实现中,Data ID默认规则是

在默认情况下,会去Nacos服务器上加载Data ID以

$(spring.application.name}.${
    
    file-extension : properties}

为前缀的基础配置。

比如当我们在bootstrap.properties文件中配置了属性

spring.application.name=spring-cloud-nacos-config-sample

在不通过spring.cloud.nacos.configprefix指定Data ID前缀时,默认会读取Nacos Config Server中Data ID为
spring-cloud-nacos-config-sample.properties的配置信息。

如果明确指定了spring.cloud.nacos.config.prefix=example属性,则会加载Data ID=example的配置。
spring.profile.active表示多环境支持,这对于Nacos也是适用的

在实际应用中,如果大家用的是YAML格式的配置,Nacos Config也提供了YAML配置格式的支持,执行步骤如下。
在bootstrap.properties中声明
spring.cloud.nacos.config.file-extension=yaml

(3)不同环境的配置切换

在Spring Boot中,可以基于spring.profiles.active实现不同环境下的配置切换,这在实际工作中用得比较多。很多公司都会有开发环境、测试环境、生产环境等,服务部署在不同的环境下,有一些配置是不同的,所以我们希望能够通过一个属性非常方便地指定当前应用部署的环境,并根据不同的环境加载对应的配置。基于Spring Boot项目的多环境支持配置步骤如下。

在Spring Cloud Alibaba Nacos Config中加载Nacos Config Server中的配置时,不仅加载了Data ID以

$(spring.application.name}.${
   
   file-extension : properties}

为前缀的基础配置,还会加载Data ID为

$(spring.applicationname)}-${profile}.$(file-extension : properties}

的基础配置,这样的方式为不同环境的切换提供了非常好的支持。

在这里插入图片描述

示例:其中 oauth-center是配置文件中spring.applicationname对应的名称,dev对应的是profile,yaml对应的是file-extension

配置方式和Spring Boot相同,具体的实现步骤如下。
在bootstrap.properties中声明spring.profiles.active=prod。需要注意的是,必须要在bootstrap.properties中声明。

基于Nacos Config实现不同环境的切换和本地配置的不同环境切换没有任何区别。如果我们需要切换到测试环境,只需要修改spring.profiles.active=test即可。不过这个属性的配置是写死在bootstrap.properties文件中的,修改起来显得很麻烦。通常的做法是通过-Dspring.profiles.active=${profile}参数来指定环境,以达到灵活切换的目的。

(三)Nacos Config 实现原理解析

(1)SDK和OpenAPI

文档参考地址:

https://nacos.io/zh-cn/docs/sdk.html
https://nacos.io/zh-cn/docs/open-api.html

【获取配置】
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException

/nacos/v1/cs/configs GET

【监听配置】
public void addListener(String dataId, String group, Listener listener)

/nacos/v1/cs/configs/listener post

【删除监听】
public void removeListener(String dataId, String group, Listener listener)

【发布配置】
public boolean publishConfig(String dataId, String group, String content) throws NacosException;

@Since 1.4.1
public boolean publishConfig(String dataId, String group, String content, String type) throws NacosException;

/nacos/v1/cs/configs POST

【删除配置】
public boolean removeConfig(String dataId, String group) throws NacosException

/nacos/v1/cs/configs DELETE

(2)配置的CRUD

对于Nacos Config来说,其实就是提供了配置的集中式管理功能,然后对外提供CRUD的访问接口使得应用系统可以完成配置的基本操作。实际上这种场景并不复杂,对于服务端来说,无非就是配置如何存储,以及是否需要持久化,对于客户端来说,就是通过接口从服务器端查询到相应的数据,然后返回即可

在这里插入图片描述

需要注意的是,Nacos服务端的数据存储默认采用的是Derby数据库,除此之外,支持MySQL数据库。如果需要修改,自定义修改成MySQL数据库的配置。

(3)动态监听之Pull Or Push

当Nacos Config Server上的配置发生变化时,需要让相关的应用程序感知配置的变化进而感知应用的变化,这就需要客户端针对感兴趣的配置实现监听。那么Nacos客户端是如何实现配置变更的实时更新的呢?

一般来说,客户端和服务端之间的数据交互无非两种方式:Pull和Push。
1、Pull表示客户端从服务端主动拉取数据。
2、Push表示服务端主动把数据推送到客户端。

这两种方式没有什么优劣之分,只是看哪种方式更适合于当前的场景。比如ActiveMQ就支持Push和Pull两种模式,用户可以在特定场景选择不同的模式来实现消费端消息的获取。

对于Push模式来说,服务端需要维持与客户端的长连接,如果客户端的数量比较多,那么服务端需要耗费大量的内存资源来保存每个连接,并且为了检测连接的有效性,还需要心跳机制来维持每个连接的状态。

在Pull模式下,客户端需要定时从服务端拉取一次数据,由于定时任务会存在一定的时间间隔,所以不能保证数据的实时性。并且在服务端配置长时间不更新的情况下,客户端的定时任务会做一些无效的Pull

Nacos采用的是Pull模式,但并不是简单的Pull ,而是一种长轮询机制,它结合Push和Pull两者的优势。客户端采用长轮询的方式定时发起Pull请求,去检查服务端配置信息是否发生了变更,如果发生了变更,则客户端会根据变更的数据获得最新的配置。所谓长轮询,是客户端发起轮询请求之后,服务端如果有配置发生变更,就直接返回。

在这里插入图片描述

如果客户端发起Pull请求后,发现服务端的配置和客户端的配置是保持一致的,那么服务端会先“Hold”住这个请求,也就是服务端拿到这个连接之后在指定的时间段内一直不返回结果,直到这段时间内配置发生变化,服务端会把原来“Hold”住的请求进行返回,如图所示,Nacos服务端收到请求之后,先检查配置是否发生了变更,如果没有,则设置一个定时任务,延期29.5s执行,并且把当前的客户端长轮询连接加入allSubs队列。这时候有两种方式触发该连接结果的返回:

第一种是在等待29.5s后触发自动检查机制,这时候不管配置有没有发生变化,都会把结果返回客户端。而29.5s就是这个长连接保持的时间。

第二种是在29.5s内任意一个时刻,通过Nacos Dashboard或者API的方式对配置进行了修改,这会触发一个事件机制,监听到该事件的任务会遍历allSubs队列,找到发生变更的配置项对应的ClientLongPolling任务,将变更的数据通过该任务中的连接进行返回,就完成了一次“推送”操作。

在这里插入图片描述

这样既能够保证客户端实时感知配置的变化,也降低了服务端的压力。其中,这个长连接的会话超时时间默认是30s。

猜你喜欢

转载自blog.csdn.net/Octopus21/article/details/114600097