天天看点

Nacos-Server注册源码分析

服务器端开放接口

nacos/v1/ns/instance 是服务器端提供的接口

Nacos架构图

Nacos-Server注册源码分析

图中可以看出来,接口应该是在NamingService相关的代码中

源码分析

在源码的naming模块中有InstanceController和InstanceControllerV2两个版本

分别对应/v1/ns/instance和/v2/ns/instance

通过@PostMapping找到具体注册方法,可以看到通过客户端发过来的数据然后解析成Instance对象交给了InstanceOperator.registerInstance方法进行注册

@PostMapping
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 = HttpRequestInstanceBuilder.newBuilder()
            .setDefaultInstanceEphemeral(switchDomain.isDefaultInstanceEphemeral()).setRequest(request).build();
    
    //判断是否使用了grpc,如果使用了就用相关的实现类进行注册
    getInstanceOperator().registerInstance(namespaceId, serviceName, instance);
    return "ok";
}
           

InstanceOperatorClientImpl 为GRPC的实现对象,现在是默认的注册对象

@Override
public void registerInstance(String namespaceId, String serviceName, Instance instance) {
    boolean ephemeral = instance.isEphemeral();
    String clientId = IpPortBasedClient.getClientId(instance.toInetAddr(), ephemeral);
    createIpPortClientIfAbsent(clientId);
    Service service = getService(namespaceId, serviceName, ephemeral);
    // 这里使用了代理服务ClientOperationServiceProxy,然后进行注册,
    // 真实的服务会在代理服务中根据是否是临时对象来确定使用对应的服务
    clientOperationService.registerInstance(service, instance, clientId);
}
           

EphemeralClientOperationServiceImpl临时客户端的操作服务实例

@Override
public void registerInstance(Service service, Instance instance, String clientId) {
    //获取服务保证使用的服务是单例的, 因为Service是重写了equals和hashcode方法的
    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()));
    }
    //根据客户端ID找到客户端,客户端信息都是存在内存中用Map存储的
    Client client = clientManager.getClient(clientId);
    if (!clientIsLegal(client, clientId)) {
        return;
    }
    //将客户端实例转换成服务端需要的实例对象
    InstancePublishInfo instanceInfo = getPublishInfo(instance);
    //将服务信息添加到服务端的客户端对象中,这里会触发ClientEvent.ClientChangeEvent
    //收到ClientChangeEvent后会触发集群同步实例
    client.addServiceInstance(singleton, instanceInfo);
    client.setLastUpdatedTime();
    NotifyCenter.publishEvent(new ClientOperationEvent.ClientRegisterServiceEvent(singleton, clientId));
    NotifyCenter
            .publishEvent(new MetadataEvent.InstanceMetadataEvent(singleton, instanceInfo.getMetadataId(), false));
}
           

发布ClientChangedEvent事件后

@Override
public void onEvent(Event event) {
    ...
    syncToAllServer((ClientEvent) event);
    ...
}
private void syncToAllServer(ClientEvent event) {
   if (event instanceof ClientEvent.ClientChangedEvent) {
        DistroKey distroKey = new DistroKey(client.getClientId(), TYPE);
        distroProtocol.sync(distroKey, DataOperation.CHANGE);
    }
}

           

发布ClientRegisterServiceEvent后,会触发建立索引,方便后续根据根据service快速查询有哪些client提供支持

private void addPublisherIndexes(Service service, String clientId) {
    publisherIndexes.computeIfAbsent(service, (key) -> new ConcurrentHashSet<>());
    publisherIndexes.get(service).add(clientId);
    NotifyCenter.publishEvent(new ServiceEvent.ServiceChangedEvent(service, true));
}