nacos registration center source code analysis 2 service discovery

nacos service discovery

Service discovery means that when the client initiates a load balancing (feign) call interface, the internal calls to the nacos server interface for the first time are
basically retrieved from the client's cache list, and will be sent to The server initiates the call

If you want to see this piece of code, you can look at ribbon source code analysisribbon source code analysis

Previous: nacos service registration

Service discovery source code analysis

NamingService provides us with service registration and service discovery functions
NacosNamingService is the implementation class of NamingService
insert image description here

@Override
public List<Instance> getAllInstances(String serviceName, String groupName, List<String> clusters,
                                      boolean subscribe) throws NacosException {
    
    

    ServiceInfo serviceInfo;
    // 判断是否需要订阅服务信息(默认为 true)
    if (subscribe) {
    
    
        // 订阅服务信息
        serviceInfo = hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName),
                                                 StringUtils.join(clusters, ","));
    } else {
    
    
        // 直接去nacos拉取服务信息
        serviceInfo = hostReactor
            .getServiceInfoDirectlyFromServer(NamingUtils.getGroupedName(serviceName, groupName),
                                              StringUtils.join(clusters, ","));
    }
    // 从服务信息中获取实例列表并返回
    List<Instance> list;
    if (serviceInfo == null || CollectionUtils.isEmpty(list = serviceInfo.getHosts())) {
    
    
        return new ArrayList<Instance>();
    }
    return list;
}

HostReactor
com.alibaba.nacos.client.naming.core.HostReactor#getServiceInfo

  public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {
    
    
        
        NAMING_LOGGER.debug("failover-mode: " + failoverReactor.isFailoverSwitch());
        String key = ServiceInfo.getKey(serviceName, clusters);
        if (failoverReactor.isFailoverSwitch()) {
    
    
            return failoverReactor.getService(key);
        }
        //读取本地服务列表的缓存,缓存是一个Map
        ServiceInfo serviceObj = getServiceInfo0(serviceName, clusters);
        //判断川村是否存在
        if (null == serviceObj) {
    
    
        	//不存在则构建信息
            serviceObj = new ServiceInfo(serviceName, clusters);
            //加入缓存
            serviceInfoMap.put(serviceObj.getKey(), serviceObj);
            //加入待更新服务列表
            updatingMap.put(serviceName, new Object());
            //更新服务列表
            updateServiceNow(serviceName, clusters);
            //从待更新列表中移除
            updatingMap.remove(serviceName);
            
        } else if (updatingMap.containsKey(serviceName)) {
    
    
             // 缓存中有,但是需要更新
            if (UPDATE_HOLD_INTERVAL > 0) {
    
    
                // hold a moment waiting for update finish
                synchronized (serviceObj) {
    
    
                    try {
    
    
                        serviceObj.wait(UPDATE_HOLD_INTERVAL);
                    } catch (InterruptedException e) {
    
    
                        NAMING_LOGGER
                                .error("[getServiceInfo] serviceName:" + serviceName + ", clusters:" + clusters, e);
                    }
                }
            }
        }
        // 开启定时更新客户端缓存服务列表
        scheduleUpdateIfAbsent(serviceName, clusters);
        
        return serviceInfoMap.get(serviceObj.getKey());
    }

**updateServiceNow(serviceName, clusters);**方法

  private void updateServiceNow(String serviceName, String clusters) {
    
    
        try {
    
    
            updateService(serviceName, clusters);
        } catch (NacosException e) {
    
    
            NAMING_LOGGER.error("[NA] failed to update serviceName: " + serviceName, e);
        }
    }

//调用远程服务
 public void updateService(String serviceName, String clusters) throws NacosException {
    
    
        ServiceInfo oldService = getServiceInfo0(serviceName, clusters);
        try {
    
    
            
            String result = serverProxy.queryList(serviceName, clusters, pushReceiver.getUdpPort(), false);
            
            if (StringUtils.isNotEmpty(result)) {
    
    
                processServiceJson(result);
            }
        } finally {
    
    
            if (oldService != null) {
    
    
                synchronized (oldService) {
    
    
                    oldService.notifyAll();
                }
            }
        }
    }



Want to initiate a call to the server
insert image description here

Timing task synchronization client cache list

scheduleUpdateIfAbsent(serviceName, clusters);

public void scheduleUpdateIfAbsent(String serviceName, String clusters) {
    
    
        if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
    
    
            return;
        }
        
        synchronized (futureMap) {
    
    
            if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
    
    
                return;
            }
            //启动定时任务
            ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, clusters));
            futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);
        }
    }

Call the run method in UpdateTask, and call the updateService method in the run method.
The updateService method has already been mentioned above.
insert image description here

The server receives the client request service discovery interface

/nacos/v1/ns/instance/list
I will not read this, it is relatively simple

The server can refer to the documentation and search for the API for pulling the service list: API for pulling the service list

Summary:
The service discovery of Nacos is divided into two modes:
Mode 1: Active pull mode, consumers actively pull the service list from Nacos regularly and cache it, and then read the service list in the local cache first when calling the service.
Mode 2: Subscription mode. Consumers subscribe to the service list in Nacos and receive service change notifications based on the UDP protocol. When the service list in Nacos is updated, a UDP broadcast will be sent to all subscribers. This one is to operate on the server interface or actively call the service registration interface or offline interface, etc., will actively push to the client the registration list that needs to be changed. Compared
with Eureka, Nacos's subscription mode service status update is more timely and easier for consumers. Discover changes in the service list in a timely manner and eliminate faulty services

Guess you like

Origin blog.csdn.net/qq_42600094/article/details/130719460