1 环境介绍
nacos版本1.4.1
2 注册入口
描述: 查看nacos官网, 请求url为:
/nacos/v1/ns/instance
描述: 找到 InstanceController类,register方法。
@CanDistro
@PostMapping
@Secured(parser = NamingResourceParser.class, action = ActionTypes.WRITE)
public String register(HttpServletRequest request) throws Exception {
final String namespaceId = WebUtils
.optional(request, CommonParams.NAMESPACE_ID, Constants.DEFAULT_NAMESPACE_ID);
final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
NamingUtils.checkServiceNameFormat(serviceName);
final Instance instance = parseInstance(request);
/**
* 服务端注册核心逻辑
*/
serviceManager.registerInstance(namespaceId, serviceName, instance);
return "ok";
}
3 核心逻辑分析
3.1 ServiceManager
描述: service注册nacos核心类。
3.2 Nacos 注册表
描述: nacos注册表采用双map结构,一套nacos 可以配置多套项目,其结构可以理解为:
(1) namespace: 用于区分项目。
(2) group: 用于区分环境(dev、release)。
(3) servcieName:微服务名称.
(4) Service:真正的服务。
用group::servcieName 确定Service。
3.3 Service
描述: Nacos中服务端的服务,存储服务采用Map结构,其Key 代表集群名称(可以用于区分地区),Cluster用于存储服务端的服务。Cluster存储服务实例又分为持久服务集,临时服务集。
3.4 registerInstance 方法
描述: ServiceManager类registerInstance方法。
public void registerInstance(String namespaceId, String serviceName, Instance instance) throws NacosException {
//创建一个空的service
createEmptyService(namespaceId, serviceName, instance.isEphemeral());
//获取service
Service service = getService(namespaceId, serviceName);
if (service == null) {
throw new NacosException(NacosException.INVALID_PARAM,
"service not found, namespace: " + namespaceId + ", service: " + serviceName);
}
//添加
addInstance(namespaceId, serviceName, instance.isEphemeral(), instance);
}
3.5 createEmptyService方法
描述: ServiceManager类createEmptyService方法。
public void createServiceIfAbsent(String namespaceId, String serviceName, boolean local, Cluster cluster)
throws NacosException {
//从注册表中获取服务
Service service = getService(namespaceId, serviceName);
//服务为空
if (service == null) {
Loggers.SRV_LOG.info("creating empty service {}:{}", namespaceId, serviceName);
//创建服务,初始化相关属性
service = new Service();
service.setName(serviceName);
service.setNamespaceId(namespaceId);
service.setGroupName(NamingUtils.getGroupName(serviceName));
// now validate the service. if failed, exception will be thrown
service.setLastModifiedMillis(System.currentTimeMillis());
service.recalculateChecksum();
if (cluster != null) {
cluster.setService(service);
service.getClusterMap().put(cluster.getName(), cluster);
}
service.validate();
//添加服务到注册表中,并且初始化心跳检测
putServiceAndInit(service);
if (!local) {
addOrReplaceService(service);
}
}
}
private void putServiceAndInit(Service service) throws NacosException {
//双重检测加入nacos注册表中
putService(service);
//采用scheduleWithFixedDelay定期检测心跳
service.init();
consistencyService
.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), true), service);
consistencyService
.listen(KeyBuilder.buildInstanceListKey(service.getNamespaceId(), service.getName(), false), service);
Loggers.SRV_LOG.info("[NEW-SERVICE] {}", service.toJson());
}
3.6 addInstance 方法
描述: ServiceManager类addInstance方法。
public void addInstance(String namespaceId, String serviceName, boolean ephemeral, Instance... ips)
throws NacosException {
//生成一个key
String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral);
//获取当前服务
Service service = getService(namespaceId, serviceName);
synchronized (service) {
//ips转instances
List<Instance> instanceList = addIpAddresses(service, ephemeral, ips);
Instances instances = new Instances();
instances.setInstanceList(instanceList);
//一致性service存放instances
consistencyService.put(key, instances);
}
}
3.7 DistroConsistencyServiceImpl
描述: put方法。
描述: 客户端向nacos发送注册请求,最终在Notifier阻塞队列中添加了注册任务。
4 Notifier 分析
描述: 任务启动,DistroConsistencyServiceImpl类初始化时,会初始化线程池开启Notifier 方法,并且当前线程corePoolSize为1。
描述: 当前类实现了Runnable接口,直接查看run方法。
@Override
public void run() {
Loggers.DISTRO.info("distro notifier started");
//自旋
for (; ; ) {
try {
//从阻塞队列中获取任务
Pair<String, DataOperation> pair = tasks.take();
//处理
handle(pair);
} catch (Throwable e) {
Loggers.DISTRO.error("[NACOS-DISTRO] Error while handling notifying task", e);
}
}
}
4.1 handle方法。
4.2 onChange
描述: Service类onChange方法会调用,updateIPs方法进行服务端ip列表的更新。
4.3 updateIPs