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));//※触发元数据事件
    }
}

一句话概括

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

相关推荐
未来之窗软件服务3 小时前
一体化系统(九)智慧社区综合报表——东方仙盟练气期
大数据·前端·仙盟创梦ide·东方仙盟·东方仙盟一体化
Lei活在当下6 小时前
【Perfetto从入门到精通】4.使用 heapprofd 工具采样追踪 Java/Native 内存分配
android·性能优化·架构
陈天伟教授6 小时前
人工智能训练师认证教程(2)Python os入门教程
前端·数据库·python
信看7 小时前
NMEA-GNSS-RTK 定位html小工具
前端·javascript·html
Tony Bai7 小时前
【API 设计之道】04 字段掩码模式:让前端决定后端返回什么
前端
苏打水com7 小时前
第十四篇:Day40-42 前端架构设计入门——从“功能实现”到“架构思维”(对标职场“大型项目架构”需求)
前端·架构
king王一帅7 小时前
流式渲染 Incremark、ant-design-x markdown、streammarkdown-vue 全流程方案对比
前端·javascript·人工智能
苏打水com7 小时前
第十八篇:Day52-54 前端跨端开发进阶——从“多端适配”到“跨端统一”(对标职场“全栈化”需求)
前端
Bigger8 小时前
后端拒写接口?前端硬核自救:纯前端实现静态资源下载全链路解析
前端·浏览器·vite