本文收录于专栏 Nacos
推荐阅读:Nacos 架构 & 原理
⚠️:使用的Nacos版本为2.4.0
前言
⚠️⚠️⚠️建议先阅读官方文档中对nacos中配置一致性模型的讲解。⚠️⚠️⚠️
本篇文章主要梳理以下逻辑
- 用户在web页面修改配置之后,服务端处理逻辑
- 服务端如何通知客户端
- 客户端接收到通知之后,如何获取最新的服务端配置
一、修改配置之后,服务端处理逻辑
页面请求接口:/nacos/v1/cs/configs?username=nacos
接口参数:
接口代码位置:config / ConfigController / publishConfig()
主要逻辑:
- 修改
config_info
表中的配置数据 - 发布配置变更事件:
ConfigDataChangeEvent
ConfigChangePublisher.notifyConfigChange(
new ConfigDataChangeEvent(false, configForm.getDataId(), configForm.getGroup(),
configForm.getNamespaceId(), configOperateResult.getLastModified()));
二、服务端对ConfigDataChangeEvent的处理
我们可以看到服务端有两处对此事件做了处理。
AsyncNotifyService
: 处理的nacos-server之间的数据逻辑,其实就是通知其它server配置发生了变更。DumpService
: 处理的就是server本身,以及server和client之间的逻辑。
本次我们只看和客户端相关的DumpService
。
三、DumpService
构造方法中向统一的事件注册中心NotifyCenter中注册了自己,且指定了事件类型为ConfigDataChangeEvent
NotifyCenter.registerSubscriber(new Subscriber() {
@Override
public void onEvent(Event event) {
handleConfigDataChange(event);
}
@Override
public Class<? extends Event> subscribeType() {
return ConfigDataChangeEvent.class;
}
});
handleConfigDataChange
的主要逻辑如下:
- 向
TaskManager
添加任务:DumpTask
- 任务被
DumpProcessor
的process(NacosTask task)
方法处理- 一系列方法流转之后,发布
LocalDataChangeEvent
事件 : ConfigCacheService.updayeMd5 - 该事件被
RpcConfigChangeNotifier
处理
- 一系列方法流转之后,发布
四、RpcConfigChangeNotifier
我们看下这个类是如何通知客户端的。
/**
1. adaptor to config module ,when server side config change ,invoke this method.
2. 3. @param groupKey groupKey
*/
public void configDataChanged(String groupKey, String dataId, String group, String tenant, boolean isBeta,
List<String> betaIps, String tag) {
//groupKey=[example+DEFAULT_GROUP] dataId + group
Set<String> listeners = configChangeListenContext.getListeners(groupKey);
if (CollectionUtils.isEmpty(listeners)) {
Loggers.REMOTE_PUSH.info("{} -- no listeners for groupKey=[{}]", getClass().getName(), groupKey);
return;
}
int notifyClientCount = 0;
for (final String client : listeners) {
Connection connection = connectionManager.getConnection(client);
if (connection == null) {
continue;
}
ConnectionMeta metaInfo = connection.getMetaInfo();
String clientIp = metaInfo.getClientIp();
String clientTag = metaInfo.getTag();
//tag check
if (StringUtils.isNotBlank(tag) && !tag.equals(clientTag)) {
continue;
}
ConfigChangeNotifyRequest notifyRequest = ConfigChangeNotifyRequest.build(dataId, group, tenant);
RpcPushTask rpcPushRetryTask = new RpcPushTask(notifyRequest,
ConfigCommonConfig.getInstance().getMaxPushRetryTimes(), client, clientIp, metaInfo.getAppName());
push(rpcPushRetryTask, connectionManager);
notifyClientCount++;
}
Loggers.REMOTE_PUSH.info("push [{}] clients, groupKey=[{}]", notifyClientCount, groupKey);
}
我们可以看到这个方法有两个重要逻辑:
- 获取监听了当前配置的所有客户端:通过
groupKey
来获取的 - 推送到客户端:根据客户端的元信息中获取客户端ip
总结
我们可以看到,当服务端的配置发生变更时,主要还是借助事件通知来封装各种处理逻辑。
最终使用groupKey获取监听的客户端,进而发送http请求通知客户端。
⚠️注意:如果你自己看过代码,你会发现,nacos的配置其实是一个三层存储
模型🤔
🤨接下来的思考:
- 客户端是如何向服务端注册指定的
groupKey
监听? - 服务端通知客户端配置发生变更之后,客户端的处理逻辑是怎样的?