本文收录于专栏 Nacos
推荐阅读:Nacos 架构 & 原理
⚠️:使用的Nacos版本为2.3.X
文章目录
- 前言
- 一、NacosConfigLoader
- 二、NacosConfigService
- 三、ClientWorker
- 四、服务端处理逻辑
- 总结
前言
上篇文章我们简单看了看Nacos客户端在启动的时候,初始化本地配置的大致流程。
本篇我们开始逐渐深入细节,先从客户端和服务端交互的相关代码入手。
一、NacosConfigLoader
上篇中我们也提到了客户端从服务端获取配置的代码:
这个nacosConfig
就是从服务端获取到的,我们看下这个load()
做了什么。
public String load(String dataId, String groupId, Properties nacosProperties) throws RuntimeException {try {//获取ConfigServiceconfigService = nacosServiceFactory != null? nacosServiceFactory.createConfigService(nacosProperties): NacosFactory.createConfigService(nacosProperties);}catch (NacosException e) {throw new RuntimeException("ConfigService can't be created with dataId :"+ dataId + " , groupId : " + groupId + " , properties : "+ nacosProperties, e);}//拿到服务端的配置内容return NacosUtils.getContent(configService, dataId, groupId);
}
NacosUtils.getContent
的实现逻辑就是从configService
中获取数据:
String content = null;
try {content = configService.getConfig(dataId, groupId, DEFAULT_TIMEOUT);
}
二、NacosConfigService
@Override
public String getConfig(String dataId, String group, long timeoutMs) throws NacosException {return getConfigInner(namespace, dataId, group, timeoutMs);
}
getConfigInner
代码如下:
private String getConfigInner(String tenant, String dataId, String group, long timeoutMs) throws NacosException {group = blank2defaultGroup(group);ParamUtils.checkKeyParam(dataId, group);ConfigResponse cr = new ConfigResponse();cr.setDataId(dataId);cr.setTenant(tenant);cr.setGroup(group);// We first try to use local failover content if exists.// A config content for failover is not created by client program automatically,// but is maintained by user.// This is designed for certain scenario like client emergency reboot,// changing config needed in the same time, while nacos server is down.String content = LocalConfigInfoProcessor.getFailover(worker.getAgentName(), dataId, group, tenant);if (content != null) {LOGGER.warn("[{}] [get-config] get failover ok, dataId={}, group={}, tenant={}, config={}",worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));cr.setContent(content);String encryptedDataKey = LocalEncryptedDataKeyProcessor.getEncryptDataKeyFailover(agent.getName(), dataId, group, tenant);cr.setEncryptedDataKey(encryptedDataKey);configFilterChainManager.doFilter(null, cr);content = cr.getContent();return content;}try {ConfigResponse response = worker.getServerConfig(dataId, group, tenant, timeoutMs, false);cr.setContent(response.getContent());cr.setEncryptedDataKey(response.getEncryptedDataKey());configFilterChainManager.doFilter(null, cr);content = cr.getContent();return content;} catch (NacosException ioe) {if (NacosException.NO_RIGHT == ioe.getErrCode()) {throw ioe;}LOGGER.warn("[{}] [get-config] get from server error, dataId={}, group={}, tenant={}, msg={}",worker.getAgentName(), dataId, group, tenant, ioe.toString());}content = LocalConfigInfoProcessor.getSnapshot(worker.getAgentName(), dataId, group, tenant);if (content != null) {LOGGER.warn("[{}] [get-config] get snapshot ok, dataId={}, group={}, tenant={}, config={}",worker.getAgentName(), dataId, group, tenant, ContentUtils.truncateContent(content));}cr.setContent(content);String encryptedDataKey = LocalEncryptedDataKeyProcessor.getEncryptDataKeySnapshot(agent.getName(), dataId, group, tenant);cr.setEncryptedDataKey(encryptedDataKey);configFilterChainManager.doFilter(null, cr);content = cr.getContent();return content;
}
以上这个方法是客户端获取config data的方法,我们可以从其中看出三个获取配置的方式:
LocalConfigInfoProcessor.getFailover
:从客户端本地一个文件中尝试获取配置,这种方式用于服务故障时临时使用。可以直接在指定地址创建文件,客户端启动时,会优先从此文件获取配置。ConfigResponse response = worker.getServerConfig(dataId, group, tenant, timeoutMs, false)
:请求Nacos服务端,获取配置数据。LocalConfigInfoProcessor.getSnapshot(worker.getAgentName(), dataId, group, tenant);
:从本地快照中获取数据。
三、ClientWorker
上文中我们看到了客户端从服务端获取数据的代码:ConfigResponse response = worker.getServerConfig(dataId, group, tenant, timeoutMs, false)
。我们接下来看看这个类是如何从服务端获取数据的。
这里可以看到是最终是发起了一个GRPC
请求去服务端
获取数据。
四、服务端处理逻辑
之前梳理服务注册时,我们了解过服务端处理GRPC
请求的入口类:GrpcRequestAcceptor
。
处理请求的主要逻辑如下:
- 从请求中获取请求类型type
- 根据type获取处理当前请求的处理类:
RequestHandler requestHandler = requestHandlerRegistry.getByRequestType(type);
- 处理请求,获取结果:
Response response = requestHandler.handleRequest(request, requestMeta);
当前请求的处理类是:ConfigQueryRequestHandler
这个类会从server端的本地缓存或者指定数据库去获取配置数据。
总结
本篇我们简单梳理了客户端和服务端在获取配置时的大致流程。可以看到客户端在启动时,优先从客户端本地去尝试获取数据,获取不到时,才会请求服务端去获取数据。