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);
...
}