nacos服务管理学习《实例注册与注销》

准备

源码链接:gitee.com/mirrors/Nac...

使用分支:v2.x-develop

核心类

NacosNamingService:命名服务入口;

NamingGrpcClientProxy:Grpc模式下命名客户端的代理;

InstanceRequestHandler:服务端用来处理实例请求的类;

EphemeralClientOperationServiceImpl:服务端暂时的实例的相关操作类

源码解读

  • 实例注册【客户端】
  1. example/src/main/java/com/alibaba/nacos/example/NamingExample.java
java 复制代码
//创建命名服务
NamingService naming = NamingFactory.createNamingService(properties);

//实例注册
naming.registerInstance(INSTANCE_SERVICE_NAME, INSTANCE_IP, INSTANCE_PORT, INSTANCE_CLUSTER_NAME);//※开始注册
  1. client/src/main/java/com/alibaba/nacos/client/naming/NacosNamingService.java
java 复制代码
@Override
public void registerInstance(String serviceName, String ip, int port, String clusterName) throws NacosException {
    registerInstance(serviceName, Constants.DEFAULT_GROUP, ip, port, clusterName);//※设置使用默认组注册实例
}

@Override
public void registerInstance(String serviceName, String groupName, String ip, int port, String clusterName)
        throws NacosException {
    //将参数封装成实例
    Instance instance = new Instance();
    instance.setIp(ip);
    instance.setPort(port);
    instance.setWeight(1.0);
    instance.setClusterName(clusterName);
    registerInstance(serviceName, groupName, instance);//※开始注册
}

@Override
public void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    //校验实例
    NamingUtils.checkInstanceIsLegal(instance);
    checkAndStripGroupNamePrefix(instance, groupName);
    
    clientProxy.registerService(serviceName, groupName, instance);//※开始注册
}
  1. client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java
java 复制代码
@Override
public void registerService(String serviceName, String groupName, Instance instance) throws NacosException {
    NAMING_LOGGER.info("[REGISTER-SERVICE] {} registering service {} with instance {}", namespaceId, serviceName,
            instance);
    if (instance.isEphemeral()) {
        //将实例注册成一个短暂的实例
        registerServiceForEphemeral(serviceName, groupName, instance);
    } else {
        doRegisterServiceForPersistent(serviceName, groupName, instance);
    }
}
private void registerServiceForEphemeral(String serviceName, String groupName, Instance instance)
        throws NacosException {
    //缓存实例
    redoService.cacheInstanceForRedo(serviceName, groupName, instance);
    //注册服务
    doRegisterService(serviceName, groupName, instance);//※马上就就要开始调服务了
}
  
/**
 * Execute register operation.
 *
 * @param serviceName name of service
 * @param groupName   group of service
 * @param instance    instance to register
 * @throws NacosException nacos exception
 */
public void doRegisterService(String serviceName, String groupName, Instance instance) throws NacosException {
    InstanceRequest request = new InstanceRequest(namespaceId, serviceName, groupName,
            NamingRemoteConstants.REGISTER_INSTANCE, instance);
    requestToServer(request, Response.class);//※真真的开始使用grpc调用服务端了。。。终于无了
    //注册后的事情【将缓存的实例标记成注册成功】
    redoService.instanceRegistered(serviceName, groupName);
}

en...其实后面还有但是我上一章已经写了grpc的源码逻辑,所以我就不写了nacos通讯方式学习《gRPC》

  • 实例注销【客户端】
  1. example/src/main/java/com/alibaba/nacos/example/NamingExample.java
java 复制代码
naming.deregisterInstance(INSTANCE_SERVICE_NAME, INSTANCE_IP, INSTANCE_PORT, INSTANCE_CLUSTER_NAME);//※开始注销实例
  1. client/src/main/java/com/alibaba/nacos/client/naming/NacosNamingService.java
java 复制代码
@Override
public void deregisterInstance(String serviceName, String ip, int port, String clusterName) throws NacosException {
    deregisterInstance(serviceName, Constants.DEFAULT_GROUP, ip, port, clusterName);//※在默认组中注销实例
}

@Override
public void deregisterInstance(String serviceName, String groupName, String ip, int port, String clusterName)
        throws NacosException {
    //将参数封装成实例
    Instance instance = new Instance();
    instance.setIp(ip);
    instance.setPort(port);
    instance.setClusterName(clusterName);
    deregisterInstance(serviceName, groupName, instance);//※开始注销实例
}

@Override
public void deregisterInstance(String serviceName, String groupName, Instance instance) throws NacosException {
    //实例校验
    NamingUtils.checkInstanceIsLegal(instance);
    checkAndStripGroupNamePrefix(instance, groupName);
    
    clientProxy.deregisterService(serviceName, groupName, instance);//※开始注销实例
}
  1. client/src/main/java/com/alibaba/nacos/client/naming/remote/gprc/NamingGrpcClientProxy.java
java 复制代码
@Override
public void deregisterService(String serviceName, String groupName, Instance instance) throws NacosException {
    NAMING_LOGGER
            .info("[DEREGISTER-SERVICE] {} deregistering service {} with instance: {}", namespaceId, serviceName,
                    instance);
    if (instance.isEphemeral()) {//判断实例是否是短暂的
        deregisterServiceForEphemeral(serviceName, groupName, instance);//※注销短暂的实例
    } else {
        doDeregisterServiceForPersistent(serviceName, groupName, instance);
    }
}

private void deregisterServiceForEphemeral(String serviceName, String groupName, Instance instance)
        throws NacosException {
    String key = NamingUtils.getGroupedName(serviceName, groupName);
    InstanceRedoData instanceRedoData = redoService.getRegisteredInstancesByKey(key);
    if (instanceRedoData instanceof BatchInstanceRedoData) {
        List<Instance> instances = new ArrayList<>();
        if (null != instance) {
            instances.add(instance);
        }
        batchDeregisterService(serviceName, groupName, instances);
    } else {
        //缓存中的实例状态修改成注销中
        redoService.instanceDeregister(serviceName, groupName);
        //开始注销
        doDeregisterService(serviceName, groupName, instance);//※马上就要注销了
    }
}
  
/**
 * Execute deregister operation.
 *
 * @param serviceName service name
 * @param groupName   group name
 * @param instance    instance
 * @throws NacosException nacos exception
 */
public void doDeregisterService(String serviceName, String groupName, Instance instance) throws NacosException {
    InstanceRequest request = new InstanceRequest(namespaceId, serviceName, groupName,
            NamingRemoteConstants.DE_REGISTER_INSTANCE, instance);
    requestToServer(request, Response.class);//※真真的开始使用grpc调用服务端了。。。终于无了
    //注销后的状态修改
    redoService.instanceDeregistered(serviceName, groupName);
}

en...注册跟注销其实是一样的逻辑,只是代码不一样而已

ps一下:nacos通讯方式学习《gRPC》

  • 实例注册【服务端】
  1. naming/src/main/java/com/alibaba/nacos/naming/remote/rpc/handler/InstanceRequestHandler.java
java 复制代码
@Override
@TpsControl(pointName = "RemoteNamingInstanceRegisterDeregister", name = "RemoteNamingInstanceRegisterDeregister")
@Secured(action = ActionTypes.WRITE)
@ExtractorManager.Extractor(rpcExtractor = InstanceRequestParamExtractor.class)
public InstanceResponse handle(InstanceRequest request, RequestMeta meta) throws NacosException {
    //将实例转成对应的服务对象
    Service service = Service.newService(request.getNamespace(), request.getGroupName(), request.getServiceName(),
            true);
    InstanceUtil.setInstanceIdIfEmpty(request.getInstance(), service.getGroupedServiceName());
    switch (request.getType()) {
        case NamingRemoteConstants.REGISTER_INSTANCE:
            return registerInstance(service, request, meta);//※接受到注册请求后开始注册实例
        case NamingRemoteConstants.DE_REGISTER_INSTANCE:
            return deregisterInstance(service, request, meta);
        default:
            throw new NacosException(NacosException.INVALID_PARAM,
                    String.format("Unsupported request type %s", request.getType()));
    }
}

private InstanceResponse registerInstance(Service service, InstanceRequest request, RequestMeta meta)
        throws NacosException {
    clientOperationService.registerInstance(service, request.getInstance(), meta.getConnectionId());//※开始注册了
    NotifyCenter.publishEvent(new RegisterInstanceTraceEvent(System.currentTimeMillis(),
            NamingRequestUtil.getSourceIpForGrpcRequest(meta), true, service.getNamespace(), service.getGroup(),
            service.getName(), request.getInstance().getIp(), request.getInstance().getPort()));
    return new InstanceResponse(NamingRemoteConstants.REGISTER_INSTANCE);
}
  1. naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java
java 复制代码
@Override
public void registerInstance(Service service, Instance instance, String clientId) throws NacosException {
    //校验实例
    NamingUtils.checkInstanceIsLegal(instance);
    //将服务对象记录到Map中,nacos管理页面的查询就是从这里来的(同时元数据也有这个数据的时候才展示)
    Service singleton = ServiceManager.getInstance().getSingleton(service);
    if (!singleton.isEphemeral()) {
        throw new NacosRuntimeException(NacosException.INVALID_PARAM,
                String.format("Current service %s is persistent service, can't register ephemeral instance.",
                        singleton.getGroupedServiceName()));
    }
    Client client = clientManager.getClient(clientId);
    checkClientIsLegal(client, clientId);
    InstancePublishInfo instanceInfo = getPublishInfo(instance);
    client.addServiceInstance(singleton, instanceInfo);
    client.setLastUpdatedTime();
    client.recalculateRevision();
    NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
    NotifyCenter
            .publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));//※触发元数据事件
}
  • 实例注销【服务端】
  1. naming/src/main/java/com/alibaba/nacos/naming/remote/rpc/handler/InstanceRequestHandler.java
java 复制代码
@Override
@TpsControl(pointName = "RemoteNamingInstanceRegisterDeregister", name = "RemoteNamingInstanceRegisterDeregister")
@Secured(action = ActionTypes.WRITE)
@ExtractorManager.Extractor(rpcExtractor = InstanceRequestParamExtractor.class)
public InstanceResponse handle(InstanceRequest request, RequestMeta meta) throws NacosException {
    Service service = Service.newService(request.getNamespace(), request.getGroupName(), request.getServiceName(),
            true);
    InstanceUtil.setInstanceIdIfEmpty(request.getInstance(), service.getGroupedServiceName());
    switch (request.getType()) {
        case NamingRemoteConstants.REGISTER_INSTANCE:
            return registerInstance(service, request, meta);
        case NamingRemoteConstants.DE_REGISTER_INSTANCE:
            return deregisterInstance(service, request, meta);//※开始注销实例
        default:
            throw new NacosException(NacosException.INVALID_PARAM,
                    String.format("Unsupported request type %s", request.getType()));
    }
}

private InstanceResponse deregisterInstance(Service service, InstanceRequest request, RequestMeta meta) {
    clientOperationService.deregisterInstance(service, request.getInstance(), meta.getConnectionId());//※开始注销实例
    NotifyCenter.publishEvent(new DeregisterInstanceTraceEvent(System.currentTimeMillis(),
            NamingRequestUtil.getSourceIpForGrpcRequest(meta), true, DeregisterInstanceReason.REQUEST,
            service.getNamespace(), service.getGroup(), service.getName(), request.getInstance().getIp(),
            request.getInstance().getPort()));
    return new InstanceResponse(NamingRemoteConstants.DE_REGISTER_INSTANCE);
}
  1. naming/src/main/java/com/alibaba/nacos/naming/core/v2/service/impl/EphemeralClientOperationServiceImpl.java
java 复制代码
@Override
public void deregisterInstance(Service service, Instance instance, String clientId) {
    if (!ServiceManager.getInstance().containSingleton(service)) {
        Loggers.SRV_LOG.warn("remove instance from non-exist service: {}", service);
        return;
    }
    Service singleton = ServiceManager.getInstance().getSingleton(service);
    Client client = clientManager.getClient(clientId);
    checkClientIsLegal(client, clientId);
    InstancePublishInfo removedInstance = client.removeServiceInstance(singleton);
    client.setLastUpdatedTime();
    client.recalculateRevision();
    if (null != removedInstance) {
        NotifyCenter.publishEvent(new ClientOperationEvent.ClientDeregisterServiceEvent(singleton, clientId));
        NotifyCenter.publishEvent(
                new MetadataEvent.InstanceMetadataEvent(singleton, removedInstance.getMetadataId(), true));//※触发元数据事件
    }
}

一句话概括

现下只学到这里,只是注册与注销。跟这块相关的还需要接着扒拉,比如:数据如何持久化存储、事件怎么订阅通知、客户端的请求如何分配处理。

相关推荐
2401_894915533 小时前
GEO 优化源码全解析:从搜索引擎到 AI 引擎的底层改写逻辑
java·服务器·前端·数据库·人工智能·分布式·搜索引擎
ZGIAI7 小时前
ZGI Workflow 并发控制:保护下游接口
人工智能·架构
ZGIAI8 小时前
知识库有结果,不等于召回率合格
人工智能·架构
Profile排查笔记8 小时前
指纹浏览器哪个好?从 Profile、代理、权限和自动化能力判断是否适合
前端·人工智能·后端·自动化
lzhdim8 小时前
12、JavaScript常见的内存泄露问题 - JavaScript学习系列文章
开发语言·前端·javascript·学习·ecmascript
denggun123458 小时前
yield
前端·数据库·python
前端snow8 小时前
ai agent -- prompt汇总
前端
老郑聊AI业财智造9 小时前
从“数字影子”到“智能共生体”:数字孪生的架构演进与产业落地全景剖析
架构
网安蟹佬霸10 小时前
WAF绕过技术实战:从规则检测到编码绕过全指南(2026最新版,附Payload集与自动化脚本)
运维·安全·网络安全·架构·自动化·网安
muddjsv10 小时前
前端性能优化实战:从加载到渲染的全面提速指南
前端·性能优化