Nacos源码8:Nacos消费端定时拉取服务实例

69 阅读1分钟

1.概述

Nacos消费端会启动定时调度,定时去Nacos服务端拉取服务实例并缓存到消费端本地Map缓存中。

2. 启动定时调度线程池

当消费端获取服务实例时,执行PollingServerListUpdater.start:启动定时调度线程池。

serverListUpdater.start(updateAction);

PollingServerListUpdater.start,启动定时调度线程池,定时更新服务实例:

public class PollingServerListUpdater implements ServerListUpdater {
   @Override
   public synchronized void start(final UpdateAction updateAction) {

      ...
      final Runnable wrapperRunnable = new Runnable() {
                @Override
                public void run() {
                    if (!isActive.get()) {
                        if (scheduledFuture != null) {
                            scheduledFuture.cancel(true);
                        }
                        return;
                    }
                    try {
                        // 更新服务实例
                        updateAction.doUpdate();
                        lastUpdated = System.currentTimeMillis();
                    } catch (Exception e) {
                        logger.warn("Failed one update cycle", e);
                    }
                }
      };

      ...
      // 定时调度线程池,定时更新服务实例
      scheduledFuture = getRefreshExecutor().scheduleWithFixedDelay(
                    wrapperRunnable,
                    initialDelayMs,
                    refreshIntervalMs,
                    TimeUnit.MILLISECONDS
       );
   }
}

NacosNamingService.selectInstances:

@Override
public List<Instance> selectInstances(String serviceName, String groupName, boolean healthy) throws NacosException {
    return selectInstances(serviceName, groupName, healthy, true);
}
  public List<Instance> selectInstances(String serviceName, String groupName, List<String> clusters, boolean healthy,
            boolean subscribe) throws NacosException {
            ...
            serviceInfo = hostReactor.getServiceInfo(NamingUtils.getGroupedName(serviceName, groupName),
                    StringUtils.join(clusters, ","));
            ...
  }

HostReactor.getServiceInfo:

public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {
   ...
   scheduleUpdateIfAbsent(serviceName, clusters);
   ...
}

HostReactor.scheduleUpdateIfAbsent:

public void scheduleUpdateIfAbsent(String serviceName, String clusters) {
     ...
     ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, clusters));
     ...
}

3. UpdateTask服务实例更新任务丢到线程池中执行

HostReactor.addTask: 在延迟任务线程池执行UpdateTask任务。

public synchronized ScheduledFuture<?> addTask(UpdateTask task) {
        return executor.schedule(task, DEFAULT_DELAY, TimeUnit.MILLISECONDS);
}

上面代码中的executor为延迟调度线程池,如下:

 public HostReactor(NamingProxy serverProxy, BeatReactor beatReactor, String cacheDir, boolean loadCacheAtStart,
            boolean pushEmptyProtection, int pollingThreadCount) {
        // init executorService
        this.executor = new ScheduledThreadPoolExecutor(pollingThreadCount, new ThreadFactory() {
            @Override
            public Thread newThread(Runnable r) {
                Thread thread = new Thread(r);
                thread.setDaemon(true);
                thread.setName("com.alibaba.nacos.client.naming.updater");
                return thread;
            }
        });
}

4. 调用Nacos服务端接口获取服务实例并缓存

有一个线程运行具体的task任务:

public class UpdateTask implements Runnable {
   ...
    @Override
    public void run() {
       ...
       // 远程调用Nacos服务端接口获取服务实例,然后缓存到消费者本地map中
       updateService(serviceName, clusters);
       ...
    }
}

远程调用Nacos服务端的/instance/list接口获取服务实例

public void updateService(String serviceName, String clusters) throws NacosException {
   ...   
   String result = serverProxy.queryList(serviceName, clusters, pushReceiver.getUdpPort(), false);
   ...   
   processServiceJson(result);
   ...
}

缓存获取的服务实例到本地map中

public ServiceInfo processServiceJson(String json) {
   ...
   ServiceInfo serviceInfo = JacksonUtils.toObj(json, ServiceInfo.class);
   ...
   serviceInfoMap.put(serviceInfo.getKey(), serviceInfo);
   ...
}