前言
Nacos 2.x 中抛弃了长轮询模式,改用长连接进行配置同步。
这次就来探探 Nacos 配置中心是如何与Spring Boot 同步变更的。
前置知识
我们在 《『Naocs 2.x』(三) Nacos 服务注册逻辑及通信过程 》的 GRPC调用过程
一小节中,分析过 Nacos Server 与 Nacos Client 的请求与响应过程。
简单地回顾一下,就是根据 Request
的具体类型不同, Nacoe Server 获取到对应的RequestHandler
,进行业务处理,最后把处理结果封装为Response
返回。
我们来看一下 Nacos Cofnig 中 Request 的层级结构 ( 只保留了与此节强相关的子类 ) :
- ConfigBatchListenRequest
Nacos Client 向 Nacos Service ,请求监听一批配置。
- ConfigQueryRequest
Nacos Client 向 Nacos Service,查询配置内容。
ps: 截图少了这个,是AbstractConfigRequest
的子类。
- ConfigChangeNotifyRequest
Nacos Server 向 Nacos Client ,推送变更配置内容的 Key。
同步配置初始化流程
NacosConfigManager
我们从 NacosConfigManager 说起,一看名字就知道,这个类绝逼持有某些重要的东西。
在 NacosConfigAutoConfiguration
配置类中:
1 | typescript复制代码@Bean |
下面进入 NacosConfigManager 中:
NacosConfigManager 持有:ConfigService(配置相关操作)、NacosConfigProperties(Spring Boot 对配置中心的配置)。
1 | java复制代码public class NacosConfigManager { |
NacosConfigService 构造函数
1 | scss复制代码// NacosConfigService # NacosConfigService(Properties properties) |
ClientWorker 构造函数
1 | ini复制代码public ClientWorker(final ConfigFilterChainManager configFilterChainManager, ServerListManager serverListManager,final Properties properties) throws NacosException { |
ConfigRpcTransportClient
ConfigRpcTransportClient 的父类为ConfigTransportClient
1 | java复制代码// ConfigTransportClient |
- listenExecutebell.poll(5L, TimeUnit.SECONDS);
获取队列头部元素,如果获取不到则等待5s。Nacos 通过这种方式来控制循环间隔。
这里需要特别注意,Nacos 通过调用notifyListenConfig()
向 listenExecutebell 设置元素的方式,来立即执行executeConfigListen()
方法。
notifyListenConfig() 方法我们在后面还会见到。
到此处同步配置的初始化流程就完成了。我们继续看同步配置的过程。
客户端同步配置
同步配置的逻辑,主要在executeConfigListen();
方法中,这段方法比较长。我们分开来看。
CacheData执行判断与分组
1 | arduino复制代码// 5 minutes to check all listen cache keys. |
处理有监听器的 CacheData
1 | scss复制代码// 标志是否有更改的配置 |
处理无监听器的 CacheData
无监听器的 CacheData 就是,从 Nacos Client 与 Nacos Server 中移除掉原有的监听器。
结尾处理
1 | scss复制代码if (needAllSync) { |
客户端接收服务端推送
当 Nacos Config 配置发生变更时,Nacos Server 会主动通知 Nacos Client。
Nacos Client 在向 Nacos Server 发送请求前,会初始化 Nacos Rpc Client,执行的方法是ConfigRpcTransportClient # ensureRpcClient(String taskId)
:
1 | scss复制代码private RpcClient ensureRpcClient(String taskId) throws NacosException { |
服务端变更通知
入口
配置变更,是在 Nacos Service 的 Web 页面进行操作的,调用POST /v1/cs/configs
接口。
该接口主要逻辑:
- 更新配置内容
- 发送配置变更事件
1 | sql复制代码persistService.insertOrUpdateTag(configInfo, tag, srcIp, srcUser, time, false); |
ConfigDataChangeEvent 监听器
AsyncNotifyService 在初始化时,向事件通知中心添加了监听器。
1 | typescript复制代码NotifyCenter.registerSubscriber(new Subscriber() { |
AsyncRpcTask异步任务
AsyncRpcTask #run()
1 | scss复制代码@Override |
接下来继续看 dumpService.dump()
:
1 | vbnet复制代码// 这里只做了一件事,就是提交异步任务 DumpTask |
DumpTask异步任务
该异步任务由 TaskManager
执行,其在EmbeddedDumpService
初始化时,被创建。
实际由TaskManager
的父类NacosDelayTaskExecuteEngine
执行processTasks()
方法:
1 | scss复制代码protected void processTasks() { |
实际上就是根据 taskKey
取到对应的NacosTaskProcessor
执行process()
方法。
此处 DumpTask
对应的是 DumpProcessor
:
1 | scss复制代码public boolean process(NacosTask task) { |
继续进入DumpConfigHandler.configDump(build.build())
:
1 | arduino复制代码public static boolean configDump(ConfigDumpEvent event) { |
继续进入ConfigCacheService.dump()
:
1 | typescript复制代码public static boolean dump(String dataId, String group, String tenant, String content, long lastModifiedTs, |
LocalDataChangeEvent 监听器
RpcConfigChangeNotifier 是 LocalDataChangeEvent 的监听器:
1 | ini复制代码@Override |
发送请求
发送请求的逻辑在RpcPushTask # run()
中:
1 | typescript复制代码public void run() { |
小结
Nacos 2.x 中弃用了 长轮询 模式,采用 长连接 模式。
- Nacos Config Client 每 5 分钟进行一次全量比对。
- Nacos Config Server 有配置发生变化时,发布
LocalDataChangeEvent
,监听器监听到该事件,即开始向 Nacos Config Client 发送ConfigChangeNotifyRequest
。Nacos Config Client 感到到有配置发生变化,向 Nacos Config Server 发送ConfigQueryRequest
请求最新配置内容。
Nacos 中大量使用了异步任务与事件机制,初次来看理解有点难度。这篇笔记内容前前后后花费了好几天时间,真让人头疼。
本文转载自: 掘金