nacos既是一个注册中心也是一个配置中心,它是二合一的。作为注册中心的原理和源码,前面的文章已经介绍过,今天开始分析nacos作为配置中心的原理和源码。
简单介绍
nacos配置中心的作用就是在微服务架构中负责集中管理各个微服务工程的配置文件,原先散落到各个微服务本地的配置文件,现在都集中存储到nacos上,这样更方便管理和维护。
nacos配置中心客户端以jar包的形式被各微服务引入,然后微服务启动的时候,会通过nacos配置中心客户端请求nacos服务端拉取该微服务对应的配置,然后把拉取到的配置加载到Environment中。
nacos有一个控制台界面,可以在上面修改配置信息。当nacos上的某个配置文件的配置被修改,nacos会通知对应的客户端发生配置变更,客户端接收到配置变更通知后,会请求nacos拉取最新的配置,并覆盖到Environment。
原理分析
下面我们从宏观的角度分析nacos的原理,不涉及到源码的解读,源码会在后续的文章中解析。
客户端启动
这里要先了解spring-cloud-context的一个接口PropertySourceLocator。
SpringBoot在启动之后,会在启动流程执行到prepareContext()方法时调用PropertySourceLocator的locate()方法,这个方法是为Environment获取配置信息用的,获取到的配置信息封装为PropertySource对象返回,然后被SpringBoot加载到Environment中。
nacos实现了Spring的PropertySourceLocator接口,实现类是NacosPropertySourceLocator。
在NacosPropertySourceLocator的locate()方法里面,会请求nacos服务端拉取配置信息,然后将配置信息放入到PropertySource对象返回。
NacosPropertySourceLocator的locate()方法里面,是通过NacosConfigService获取的,NacosConfigService会通过RPC远程调用请求到nacos服务端。
服务端启动
nacos配置中心服务端启动时,会调用DumpService从数据库中分页查询配置信息,如果我们配置的是存储到MySQL,那么就是分页查询MySQL中存储的配置信息。然后DumpService会调用ConfigCacheService把查询到的配置信息dump到磁盘成为一个一个的配置文件(xxx.yaml、xxx.properties),每个DataId对应一个配置文件。
然后服务端接收到获取配置文件的请求时,是从磁盘中查询对应文件返回的,而不是去查询数据库,因此我们如果直接在MySQL中修改配置信息,客户端是感知不到的。
除此以外ConfigCacheService还会给每个配置文件算出一个MD5值,然后根据dataId、group、tenant三元组得到一个key,把key与该MD5值缓存起来。
最后ConfigCacheService异步给客户端发送一个配置变更通知。
那么加上客户端启动的流程,目前的整体流程是这样:
配置新增或修改
当我们在nacos-console控制界面上新增或修改了配置并发布后,就会通过http请求调用到ConfigController的publishConfig()方法。
ConfigController的publishConfig()方法会马上把新增或修改的配置持久化到MySQL。
配置持久化到MySQL之后,会异步的进行配置dump到磁盘文件以及在nacos集群间的同步。
配置dump到磁盘文件还是通过DumpService进行,先把新增或修改的配置dump到磁盘文件,然后根据文件内容算出一个MD5值与缓存中的MD5值进行比较,发现两MD5值不一致,说明发生了配置内容的变更,需要更新MD5值并通知客户端。
加上前面的客户端和服务端的启动流程,目前的整体流程是这样子:
客户端监听配置变更并刷新
在nacos配置中心客户端启动的时候,会监听通过NacosContextRefresher监听ApplicationReadyEvent事件。
在SpringBoot启动完成后,会调用发布ApplicationReadyEvent事件,NacosContextRefresher会监听到该事件,并进行处理。
NacosContextRefresher会给当前客户端引用的每个配置文件创建一个CacheData对象并在其中添加一个监听器Listener。这个Listener不是Spring事件监听机制的Listener,是nacos定义的一个Listener接口。
这里添加的这个Listener,它的作用就是在监听到有配置变更时发布一个RefreshEvent事件。
这个CacheData对象包含了配置文件的dataId、group、tenant(也就是namespace)、配置文件内容content,配置文件MD5,,监听器列表listeners等。
在nacos配置中心客户端启动的时候,会创建NacosConfigService,在NacosConfigService的构造方法中会创建ClientWorker,在ClientWorker初始化时会启动定时任务。
ClientWorker的定时任务会通过http请求获取服务端中发生变更的DataID列表,然后根据这些DataID列表请求对应的配置文件内容content,再把content赋值到CacheData并重新计算MD5值,然后跟CacheData的listeners中每个Listener保存的老MD5值比较,如果不一致,就会调用Listener的receiveConfigInfo()方法,而NacosContextRefresher中添加的Listener的receiveConfigInfo()方法就会发布一个RefreshEvent事件。
发布的RefreshEvent事件是Spring事件监听机制的事件对象,会被RefreshEventListener监听并接收,RefreshEventListener会进行配置的刷新处理。这个RefreshEventListener是spring-cloud-context包中的对象,也就是说配置刷新是spring-cloud提供的公共逻辑,不是nacos实现的,nacos只要发布一个RefreshEvent事件即可触发。
综上所述,nacos配置中心的整个宏观流程就是一下这样:
这里只是对nacos的大体流程梳理了一下,还没有涉及到源码的分析,源码的分析会在后续的文章中展开描述。