Nacos的配置中心源码解读学习
本文来源参考 https://www.jianshu.com/p/1dd59c113287
源码来源参考Nacos官方 https://github.com/alibaba/nacos.git
本文基于1.3.2版本,进行了源码复读和验证,差异化的地方做了标注,如有问题可指出,不胜感激
文章主要以文字的形式展现,没有粘贴源代码,自己可以根据看的文字,结合源代码再点的看一遍,可以加深理解。
Nacos的配置中心
目标:主要针对实现配置化管理,实现服务和配置分离,实现配置更新及时生效。
以Nacos的可视化console为例,结合具体的页面增删改操作和对应的代码如何,分析具体的源码实现过程。
关键概念:明确配置中心的关键key:DataId,决定了我们的数据域,配置相同dataId下的配置时共享的,同样的key取得相同的数据。
Nacos 数据模型 Key 由三元组唯一确定, Namespace默认是空串,公共命名空间(public),分组默认是 DEFAULT_GROUP
这里插入几张图片,对Nacos大致有个了解
1、Nacos1.3.X版本变动
2、源码包结构说明
3、模块依赖关系说明
一、ConfigService
Nacos的配置中心关键入口是ConfigService
1、加载配置文件到properties
2、反射获取带参Properties构造方法
3、创建http连接器,异步启动处理;
4、初始化一个线程池(根据定时器的检查情况决定是否启动其他任务)和一个定时器(定时检查配置信息,ClientWorker 中new LongPollingRunnable())
二、配置信息的获取
String content = configService.getConfig(dataId, group, 5000);
客户端处理:
1、优先获取本地配置,没有再远程拉取;
2、远程获取后会缓存快照到本地;
3、集群情况下远程拉取会根据权重和超时来控制,一次拉取失败后会根据重试次数重试,直到成功或超时;
服务端处理:
1、接收请求参数,检查请求参数;
2、同步获取(自旋锁),单机或者非mysql的使用sql查询;
3、否则磁盘文件获取,没查到直接返回,查到的处理后返回,并记录日志;
4、若2,同步获取锁失败后,查询失败,返回具体失败信息;
三、配置信息更新
boolean isPublishOk = configService.publishConfig(dataId, group, content);
1、数据库持久化;
2、事件触发,后续会通知其他节点 都同步更新数据到本地缓存
3、2中具体的实现过程基于常用的task和轮询处理以及失败继续处理机制;
注意:
4、这里我基于master 1.3.2的版本源码查看的时候,已经替换了原来的EventDispatcher.fireEvent 为 ConfigChangePublisher.notifyConfigChange,然后又调用 NotifyCenter.publishEvent(ConfigDataChangeEvent),可以看到替换成了订阅推送模式,根据具体的订阅者(DumpConfigHandler,不对的,具体看下面的更新过程)去执行。
5、本地config更新过程:
第一部分:
MemoryMonitor(构建了几个定时器) -> new NotifyTaskQueueMonitorTask -> AsyncNotifyService(notifySingleService) -> ServerMemberManager -> registerSubscriber(ConfigDataChangeEvent)
-> ConfigExecutor.executeAsyncNotify(new AsyncTask(httpclient, queue)); -> AsyncTask.executeAsyncInvoke()
第二部分:
-> 继续调用服务端接口CommunicationController(通知其他节点的服务)中 /dataChange -> dumpService.dump() -> TaskManager.process()
-> processor.process() [这里用到了DumpProcessor] -> DumpConfigHandler.configDump(build.build()) -> ConfigCacheService.dump() -> DiskUtil.saveToDisk()
-> 继续通知 NotifyCenter.publishEvent(new LocalDataChangeEvent(groupKey));
备注:这块之前看错了,看成了根据具体的订阅者(DumpConfigHandler)去执行,事实上不是,实际是经过了一个过程的,都是定时器在轮询,就如上面所说的调用过程。
阅读源码的过程中不明白的问题,后来又看明白的:
(1)NotifyCenter中publisherMap 什么时候构建的?
(2)DefaultPublisher中subscribers什么时候注册的订阅者?
以上两个问题回答:都针对这个配置更新这块,AsyncNotifyService构建过程中注册了一个匿名内部类,处理ConfigDataChangeEvent
6、本地缓存更新
ClientWorker 中new LongPollingRunnable() 执行,在创建NacosConfigService时创建定时器
-> checkUpdateDataIds()
-> 请求服务 /listener -> ConfigController(listener()) -> doPollingConfig() -> addLongPollingClient()
-> ClientLongPolling() -> 中间有更新时继续执行 注册的 LocalDataChangeEvent
此时由 LongPollingService() 构建中注册LocalDataChangeEvent -> DataChangeTask() -> 完毕后清除订阅者
四、服务启动数据加载 和 服务之间健康检查
没有细看,大致和原文说的差不多。