Nacos源码学习系列服务端第1篇服务注册之主流程

服务端注册会分三块讲解

  1. 主流程讲解
  2. client管理
  3. 注册过程中发布的事件

服务注册流程图

注册请求入口

方法上的 @CanDistro 和 @Secured注解后面再作说明

这里的Instance 对象的属性跟 客户端篇 的Instance 对象的属性是一样的这里部赘述

@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + UtilsAndCommons.NACOS_NAMING_INSTANCE_CONTEXT)
public class InstanceController {
        
        @CanDistro
        @PostMapping
        @Secured(action = ActionTypes.WRITE)
        public String register(HttpServletRequest request) throws Exception {

        //读取请求的namespaceId字段值 默认时public
        final String namespaceId = WebUtils
                .optional(request, CommonParams.NAMESPACE_ID, 
        Constants.DEFAULT_NAMESPACE_ID);
        //读取请求的服务名称字段值   格式要求groupname@@servicename   
        final String serviceName = WebUtils.required(request, CommonParams.SERVICE_NAME);
        //服务名称格式校验 
        NamingUtils.checkServiceNameFormat(serviceName);
        //封装Instance 对象
        final Instance instance = HttpRequestInstanceBuilder.newBuilder()
                         .setDefaultInstanceEphemeral(
        switchDomain.isDefaultInstanceEphemeral()).
        setRequest(request).build();
        //这里 getInstanceOperator() 得到的是 InstanceOperatorClientImpl 类型对象
        getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
        return "ok";
    }
}

需要注意的是 构建instance 对象时instanceId 的生成逻辑

格式比如: ip#port#clusterName#serviceName

 

public class HttpRequestInstanceBuilder {
   ...
   //设置instanceid
   private void setInstanceId(Instance instance) {
        DefaultInstanceIdGenerator idGenerator = new    
        DefaultInstanceIdGenerator(instance.getServiceName(),
                instance.getClusterName(), instance.getIp(), instance.getPort());
        instance.setInstanceId(idGenerator.generateInstanceId());
    }
   ...
}

//instance id 生成器
public class DefaultInstanceIdGenerator implements IdGenerator {
    public static final String ID_DELIMITER = "#";
    public String generateInstanceId() {
        return ip + ID_DELIMITER + port + ID_DELIMITER + clusterName + ID_DELIMITER + 
        serviceName;
    }
}

处理请求

创建客户端

public class InstanceOperatorClientImpl implements InstanceOperator {
    @Override
    public void registerInstance(String namespaceId, String serviceName, Instance instance) 
         {
        //是否时临时实例 目前为止我们的实例都是临时的 
        boolean ephemeral = instance.isEphemeral();
        //生成一个客户端id 用ip 和 端口表示一个客户端 格式ip#port
        String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);
        //根据客户端id创建客户端
        createIpPortClientIfAbsent(clientId);
        //创建一个服务
        Service service = getService(namespaceId, serviceName, ephemeral);
        //clientOprationService 这里的类型时 ClientOperationServiceProxy 代理类
        clientOperationService.registerInstance(service, instance, clientId);
      }
    
}

public class Service {
   ...
    private Service(String namespace, String group, String name, boolean ephemeral) {
        this.namespace = namespace;
        this.group = group;
        this.name = name;
        this.ephemeral = ephemeral;
        revision = new AtomicLong();
        lastUpdatedTime = System.currentTimeMillis();
    } 
   ...
}

这一步生成了client id ,并创建了client。下面是官方对client的注释:

AbstractClient:The abstract concept of the client stored by on the server of Nacos naming module. It is used to store which services the client has published and subscribed。
IpPortBasedClient:The client is bind to the ip and port users registered. It's a abstract content to simulate the tcp session client
下一章节详细解读client. 
ClientOperationServiceProxy 是一个代理类他背后的逻辑是根据实例是否是临时节点选择相应的处理类完成实例注册
Service:不会记录ip port等信息 revision\lastUpdatedTime 这两个字段目前都是赋予初始值.等后面使用到的时候再做了解

 选择正确的处理类

public class ClientOperationServiceProxy {

    //根据实例的持久化特性选择不同的处理类完成注册实例
    @Override
    public void registerInstance(Service service, Instance instance, String clientId) {
        final ClientOperationService operationService = 
                chooseClientOperationService(instance);
        //operationService 在这里的类型是: EphemeralClientOperationService
        operationService.registerInstance(service, instance, clientId);
    }

     //临时节点使用 ephemeralClientOperationService  
     //持久化节点使用 persistentClientOperationService
     private ClientOperationService chooseClientOperationService(final Instance instance) {
        return instance.isEphemeral() ? ephemeralClientOperationService : 
               persistentClientOperationService;
     }
}

 EphemeralClientOperationServiceImpl  完成注册请求

public class EphemeralClientOperationServiceImpl implements ClientOperationService {
    @Override
    public void registerInstance(Service service, Instance instance, String clientId) {
       //先检查该服务是否在服务管理器中注册过么有就注册 
       Service singleton = ServiceManager.getInstance().getSingleton(service);
        ...
        //获取之前注册过的IpPortBasedClient对象
        Client client = clientManager.getClient(clientId);
        ...
        //从instance对象创建InstancePublishInfo 
        //注意包括ip port healthy 3个属性 是instance的属性的子集
        InstancePublishInfo instanceInfo = getPublishInfo(instance);
        
        client.addServiceInstance(singleton, instanceInfo);
        client.setLastUpdatedTime();
        //注册完成发布事件
        NotifyCenter.publishEvent(new 
             ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
        NotifyCenter.publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, 
        instanceInfo.getMetadataId(), false));
    }
}

public class AbstractClient {
    //记录客户端上发布的服务信息
    protected final ConcurrentHashMap<Service, InstancePublishInfo> publishers = new ConcurrentHashMap<>(16, 0.75f, 1);
      //...  
    protected final ConcurrentHashMap<Service, Subscriber> subscribers = new ConcurrentHashMap<>(16, 0.75f, 1);

    .... 

    @Override
    public boolean addServiceInstance(Service service, InstancePublishInfo 
              instancePublishInfo) {
        //  客户端务发布服务实例布信息
        if (null == publishers.put(service, instancePublishInfo)) {
            MetricsMonitor.incrementInstanceCount();
        }
        //统一事件中心:客户端变化事件  
        NotifyCenter.publishEvent(new ClientEvent.ClientChangedEvent(this));
        return true;
    ....
    }
}

总结

核心流程逻辑比较简单注意包括下面几个步骤:

1、创建Instance

2、创建Client

3、创建Service

4、Client 添加注册实例

5、发布变更事件

下一章节我们介绍Client

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值