Nacos 注册中心实现原理,及服务注册源码分析

1、关于 Nacos

 

Nacos 的关键特性包括:

  • 服务发现和服务健康监测。
  • 动态配置服务。
  • 动态 DNS 服务。
  • 服务及其元数据管理

在这里插入图片描述

 

2、Nacos 架构图

 
在这里插入图片描述

 

3、Nacos 注册中心原理

 

服务注册的功能主要体现在以下几个方面:

  • 服务实例在启动时注册到服务注册列表,并在关闭时注销。
  • 服务消费者查询服务注册列表,获得可用实例。
  • 服务注册中心需要调用服务实例的健康检查 API ,来验证服务提供者是否能够处理请求。

在这里插入图片描述

 

4、Spring Cloud 框架下 Nacos 的服务注册

 

  • 带着一个问题,往下看博文:Spring Cloud 是何时完成服务注册的 ?
     

4.1、先从 spring.factory 文件说起

 

  • spring.factory 文件的功能

       springboot项目开发过程中,我们加载自己写的bean,只需要在该类上加上@Component注解,然后过程启动会扫描启动类所在的包及其子包。有些场景是我们需要的bean,在第三方包中就不好使用@Component注解。当然不排除通过其他注解可以import进来。我们要知道使用spring.factories文件的方法,也可以解决这种问题。
 
       假设我们有一个xxx.jar包,里面有一个bean,我们期望工程启动的时候就加载这个bean到容器,xxx.jar包是提供给其他人使用的,其他工程的启动了类所在的路径不能覆盖这个bean所在的包路径,通过ComponouneScan扫描太麻烦了,而且需求是工程启动后就加载bean,我们可以使用spring.factories文件的方法。
 
       在xxx.jar包下面的resources下面新建文件/META-INF/spring.factories文件,在spring.factories文件中配置相关需要加载的类即可。具体请详细查询spring.factories文件用法,这里知识简要说明spring.factories文件的功能。

 

4.2、Spring Cloud 集成 Nacos 的过程

 
        在 spring-cloud-commons 包的 /META-INF/spring.factories 文件中,包含了自动装配的配置信息,见以下截图,其中包含类:org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationAutoConfiguration
 
 
在这里插入图片描述
 

4.3、客户端 服务注册、心跳检测的源码分析

 

  • 注意,以下源码的版本为:
       <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
            <version>0.2.1.RELEASE</version>
        </dependency>

在这里插入图片描述

 

  • 1、看 AutoServiceRegistrationAutoConfiguration 类源码,可以看到它注入了 AutoServiceRegistration 实例。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.client.serviceregistry;

import javax.annotation.PostConstruct;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({AutoServiceRegistrationConfiguration.class})
@ConditionalOnProperty(
    value = {"spring.cloud.service-registry.auto-registration.enabled"},
    matchIfMissing = true
)
public class AutoServiceRegistrationAutoConfiguration {
    @Autowired(
        required = false
    )
    // 注入 AutoServiceRegistration 实例
    private AutoServiceRegistration autoServiceRegistration;
    @Autowired
    private AutoServiceRegistrationProperties properties;

    public AutoServiceRegistrationAutoConfiguration() {
    }

    @PostConstruct
    protected void init() {
        if (this.autoServiceRegistration == null && this.properties.isFailFast()) {
            throw new IllegalStateException("Auto Service Registration has been requested, but there is no AutoServiceRegistration bean");
        }
    }
}

 

  • 2、查看 AutoServiceRegistration 相关类图,AbstractAutoServiceRegistration 抽象类实现了AutoServiceRegistration 接口类NacosAutoServiceRegistration 类继承了 AbstractAutoServiceRegistration 抽象类

在这里插入图片描述
 

  • 3、分析下 AbstractAutoServiceRegistration 抽象类源码,具体看源码中添加的注释说明。

package org.springframework.cloud.client.serviceregistry;

import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import javax.annotation.PreDestroy;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.BeansException;
import org.springframework.boot.web.context.ConfigurableWebServerApplicationContext;
import org.springframework.boot.web.context.WebServerInitializedEvent;
import org.springframework.cloud.client.discovery.ManagementServerPortUtils;
import org.springframework.cloud.client.discovery.event.InstancePreRegisteredEvent;
import org.springframework.cloud.client.discovery.event.InstanceRegisteredEvent;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.event.EventListener;
import org.springframework.core.env.Environment;

public abstract class AbstractAutoServiceRegistration<R extends Registration> implements AutoServiceRegistration, 
                                                                              ApplicationContextAware {
    private static final Log logger = LogFactory.getLog(AbstractAutoServiceRegistration.class);
    private boolean autoStartup = true;
    private AtomicBoolean running = new AtomicBoolean(false);
    private int order = 0;
    private ApplicationContext context;
    private Environment environment;
    private AtomicInteger port = new AtomicInteger(0);
    
    // 这里是服务注册 ServiceRegistry 接口类, NacosAutoServiceRegistration 继承 AbstractAutoServiceRegistration 时,
    // 指定了 R 为 NacosRegistration
    private final ServiceRegistry<R> serviceRegistry;
    
    private AutoServiceRegistrationProperties properties;

    protected AbstractAutoServiceRegistration(ServiceRegistry<R> serviceRegistry, 
                                            AutoServiceRegistrationProperties properties) {
        this.serviceRegistry = serviceRegistry;
        this.properties = properties;
    }

    protected ApplicationContext getContext() {
        return this.context;
    }

    // @EventListener 事件监听机制,监听某个指定事件。这里 @EventListener({WebServerInitializedEvent.class}) 表示:
    //  监听 WebServerInitializedEvent 事件(当 Webserver 初始化完成之后)执行
    @EventListener({WebServerInitializedEvent.class})
    public void bind(WebServerInitializedEvent event) {
        ApplicationContext context = event.getApplicationContext();
        if (!(context instanceof ConfigurableWebServerApplicationContext) || 
        !"management".equals(((ConfigurableWebServerApplicationContext)context).getServerNamespace())) {
            this.port.compareAndSet(0, event.getWebServer().getPort());
            // 执行start()方法,往下详细看该类 start() 方法
            this.start();
        }
    }

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
        this.environment = this.context.getEnvironment();
    }


    public boolean isAutoStartup() {
        return this.autoStartup;
    }

    public void start() {
        if (!this.isEnabled()) {
            if (logger.isDebugEnabled()) {
                logger.debug("Discovery Lifecycle disabled. Not starting");
            }

        } else {
            if (!this.running.get()) {
                this.context.publishEvent(new InstancePreRegisteredEvent(this, this.getRegistration()));
                // 这里调用 该类中注册方法,往下详细看 register() 方法
                this.register();
                if (this.shouldRegisterManagement()) {
                    this.registerManagement();
                }

                this.context.publishEvent(new InstanceRegisteredEvent(this, this.getConfiguration()));
                this.running.compareAndSet(false, true);
            }

        }
    }

    protected boolean shouldRegisterManagement() {
        if (this.properties != null && !this.properties.isRegisterManagement()) {
            return false;
        } else {
            return this.getManagementPort() != null && ManagementServerPortUtils.isDifferent(this.context);
        }
    }

    // …… 
    // 该类中的部分方法函数,在此次删减掉了。想详细了解该类,可以看相关完整源码。此处仅详细关注服务注册相关。 
    // …… 
    

    protected ServiceRegistry<R> getServiceRegistry() {
        return this.serviceRegistry;
    }

    protected void register() {
    
        // 这里调用 serviceRegistry 接口类中的 register() 方法。
        // 往下深究你会发现,NacosServiceRegistry implements ServiceRegistry<NacosRegistration>
        // NacosServiceRegistry 类实现了 ServiceRegistry 接口类
        this.serviceRegistry.register(this.getRegistration());
    }

    protected void registerManagement() {
        R registration = this.getManagementRegistration();
        if (registration != null) {
            this.serviceRegistry.register(registration);
        }

    }

    protected void deregister() {
        this.serviceRegistry.deregister(this.getRegistration());
    }

    protected void deregisterManagement() {
        R registration = this.getManagementRegistration();
        if (registration != null) {
            this.serviceRegistry.deregister(registration);
        }

    }

    public void stop() {
        if (this.getRunning().compareAndSet(true, false) && this.isEnabled()) {
            this.deregister();
            if (this.shouldRegisterManagement()) {
                this.deregisterManagement();
            }

            this.serviceRegistry.close();
        }

    }
}

 

  • 4、NacosAutoServiceRegistration 类 源码分析
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.alibaba.nacos.registry;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.serviceregistry.AbstractAutoServiceRegistration;
import org.springframework.cloud.client.serviceregistry.AutoServiceRegistrationProperties;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

// NacosAutoServiceRegistration 继承了 AbstractAutoServiceRegistration 抽象类,并指定了 NacosRegistration
public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<NacosRegistration> {
    private static final Logger LOGGER = LoggerFactory.getLogger(NacosAutoServiceRegistration.class);
    @Autowired
    private NacosRegistration registration;

    public NacosAutoServiceRegistration(ServiceRegistry<NacosRegistration> serviceRegistry, 
          AutoServiceRegistrationProperties autoServiceRegistrationProperties, NacosRegistration registration) {
        super(serviceRegistry, autoServiceRegistrationProperties);
        this.registration = registration;
    }

    /** @deprecated */
    @Deprecated
    public void setPort(int port) {
        this.getPort().set(port);
    }

    protected NacosRegistration getRegistration() {
        if (this.registration.getPort() < 0 && this.getPort().get() > 0) {
            this.registration.setPort(this.getPort().get());
        }

        Assert.isTrue(this.registration.getPort() > 0, "service.port has not been set");
        return this.registration;
    }

    protected NacosRegistration getManagementRegistration() {
        return null;
    }
    
    // 重点是该方法 
    protected void register() {
        if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
            LOGGER.debug("Registration disabled.");
        } else {
            // NacosRegistration 设置相关参数
            if (this.registration.getPort() < 0) {
                this.registration.setPort(this.getPort().get());
            }
            // 最终还是调用了 父类  AbstractAutoServiceRegistration 的 register 方法。
            super.register();
        }
    }

    protected void registerManagement() {
        if (this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
            super.registerManagement();
        }
    }

    protected Object getConfiguration() {
        return this.registration.getNacosDiscoveryProperties();
    }

    protected boolean isEnabled() {
        return this.registration.getNacosDiscoveryProperties().isRegisterEnabled();
    }

    protected String getAppName() {
        String appName = this.registration.getNacosDiscoveryProperties().getService();
        return StringUtils.isEmpty(appName) ? super.getAppName() : appName;
    }
}

 

  • 5、NacosServiceRegistry 类 源码分析,实现了 ServiceRegistry< NacosRegistration>接口类
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.cloud.alibaba.nacos.registry;

import com.alibaba.nacos.api.naming.NamingService;
import com.alibaba.nacos.api.naming.pojo.Instance;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.client.serviceregistry.ServiceRegistry;
import org.springframework.util.StringUtils;

public class NacosServiceRegistry implements ServiceRegistry<NacosRegistration> {
    private static Logger logger = LoggerFactory.getLogger(NacosServiceRegistry.class);

    public NacosServiceRegistry() {
    }
    
    // 主要是该方法,实现了 ServiceRegistry 接口类的 register(Registration) 方法
    public void register(NacosRegistration registration) {
        if (!registration.isRegisterEnabled()) {
            logger.info("Nacos Registration is disabled...");
        } else if (StringUtils.isEmpty(registration.getServiceId())) {
            logger.info("No service to register for nacos client...");
        } else {
            // 获取到  NamingService 服务
            NamingService namingService = registration.getNacosNamingService();
            String serviceId = registration.getServiceId();
            Instance instance = new Instance();
            instance.setIp(registration.getHost());
            instance.setPort(registration.getPort());
            instance.setWeight((double)registration.getRegisterWeight());
            instance.setClusterName(registration.getCluster());
            instance.setMetadata(registration.getMetadata());

            try {
                // 通过该方法,进行服务注册
                namingService.registerInstance(serviceId, instance);
                logger.info("nacos registry, {} {}:{} register finished", new Object[]{serviceId, instance.getIp(), instance.getPort()});
            } catch (Exception var6) {
                logger.error("nacos registry, {} register failed...{},", new Object[]{serviceId, registration.toString(), var6});
            }

        }
    }

    public void deregister(NacosRegistration registration) {
        logger.info("De-registering from Nacos Server now...");
        if (StringUtils.isEmpty(registration.getServiceId())) {
            logger.info("No dom to de-register for nacos client...");
        } else {
            NamingService namingService = registration.getNacosNamingService();
            String serviceId = registration.getServiceId();

            try {
                namingService.deregisterInstance(serviceId, registration.getHost(), registration.getPort(), registration.getCluster());
            } catch (Exception var5) {
                logger.error("ERR_NACOS_DEREGISTER, de-register failed...{},", registration.toString(), var5);
            }

            logger.info("De-registration finished.");
        }
    }

    public void close() {
    }

    public void setStatus(NacosRegistration registration, String status) {
    }

    public <T> T getStatus(NacosRegistration registration) {
        return null;
    }
}

 

  • 6、NacosNamingService 类 源码分析,实现了 NamingService接口类
public class NacosNamingService implements NamingService {
    private String namespace;
    private String endpoint;
    private String serverList;
    private String cacheDir;
    private String logName;
    private HostReactor hostReactor;
    private BeatReactor beatReactor;
    private EventDispatcher eventDispatcher;
    private NamingProxy serverProxy;

    private void init() {
        this.namespace = System.getProperty("namespace");
        if (StringUtils.isEmpty(this.namespace)) {
            this.namespace = "default";
        }

        this.logName = System.getProperty("com.alibaba.nacos.naming.log.filename");
        if (StringUtils.isEmpty(this.logName)) {
            this.logName = "naming.log";
        }

        String logLevel = System.getProperty("com.alibaba.nacos.naming.log.level");
        if (StringUtils.isEmpty(logLevel)) {
            logLevel = "INFO";
        }

        LogUtils.setLogLevel(logLevel);
        this.cacheDir = System.getProperty("com.alibaba.nacos.naming.cache.dir");
        if (StringUtils.isEmpty(this.cacheDir)) {
            this.cacheDir = System.getProperty("user.home") + "/nacos/naming/" + this.namespace;
        }

    }

    public NacosNamingService(String serverList) {
        this.serverList = serverList;
        this.init();
        this.eventDispatcher = new EventDispatcher();
        this.serverProxy = new NamingProxy(this.namespace, this.endpoint, serverList);
        this.beatReactor = new BeatReactor(this.serverProxy);
        this.hostReactor = new HostReactor(this.eventDispatcher, this.serverProxy, this.cacheDir, false);
    }

    
    // 上面 5、中调用 namingService.registerInstance(serviceId, instance); 的具体实现
    public void registerInstance(String serviceName, Instance instance) throws NacosException {
        BeatInfo beatInfo = new BeatInfo();
        beatInfo.setDom(serviceName);
        beatInfo.setIp(instance.getIp());
        beatInfo.setPort(instance.getPort());
        beatInfo.setCluster(instance.getClusterName());
        beatInfo.setWeight(instance.getWeight());
        beatInfo.setMetadata(instance.getMetadata());
        // 通过 beatReactor.addBeatInfo 方法 创建心跳信息实现健康检测, 
        // Nacos Server 必须要确保注册的服务实例是健康的
        // 心跳检测就是服务健康检测的手段。详细见下面第 7步
        this.beatReactor.addBeatInfo(serviceName, beatInfo);
        // serverProxy.registerService 方法实现服务注册,详情见下面第 8步
        this.serverProxy.registerService(serviceName, instance);
    }

   // ……
   // 该类的源码在这里被省略部分方法,如需了解该类完整源码,可查看相关文档。
   // …… 


 

  • 7、BeatReactor 类 源码分析 心跳检测机制,从源码上来看,所谓的心跳检测机制,就是客户端定时的向服务端发送请求。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.alibaba.nacos.client.naming.beat;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.nacos.client.naming.net.NamingProxy;
import com.alibaba.nacos.client.naming.utils.LogUtils;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class BeatReactor {
    // 定时调度线程池 ScheduledThreadPoolExecutor 做定时任务处理
    private ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
        public Thread newThread(Runnable r) {
            Thread thread = new Thread(r);
            // 设置线程为“守护线程”
            thread.setDaemon(true);
            // BeatReactor 会启动名为 com.alibaba.nacos.naming.beat.sender 的线程来发送心跳,
            // 默认线程数为1~CPU核心数的一半,可由namingClientBeatThreadCount参数指定。
            thread.setName("com.alibaba.nacos.naming.beat.sender");
            return thread;
        }
    });
    
    // 这里定义了默认 5秒 发送一次心跳,可根据Nacos服务端返回的clientBeatInterval的值调整心跳间隔。
    private long clientBeatInterval = 5000L;
    private NamingProxy serverProxy;
    
    // 成员变量Map<String, BeatInfo> dom2Beat 中保存了需要发送的 BeatInfo,
    // key为{serviceName}#{ip}#{port},value为对应的BeatInfo
    public final Map<String, BeatInfo> dom2Beat = new ConcurrentHashMap();

    public BeatReactor(NamingProxy serverProxy) {
        this.serverProxy = serverProxy;
        // scheduleAtFixedRate 方法的左右是指定频率执行方法
        // 这里指 每5秒执行一次 new BeatReactor.BeatProcessor() 。 clientBeatInterval指执行间隔,默认为5秒
        this.executorService.scheduleAtFixedRate(new BeatReactor.BeatProcessor(), 0L, this.clientBeatInterval, TimeUnit.MILLISECONDS);
    }
     
    // 此处衔接上面第 6 步 
    public void addBeatInfo(String dom, BeatInfo beatInfo) {
        LogUtils.LOG.info("BEAT", "adding service:" + dom + " to beat map.");
        this.dom2Beat.put(this.buildKey(dom, beatInfo.getIp(), beatInfo.getPort()), beatInfo);
    }

    public void removeBeatInfo(String dom, String ip, int port) {
        LogUtils.LOG.info("BEAT", "removing service:" + dom + " from beat map.");
        this.dom2Beat.remove(this.buildKey(dom, ip, port));
    }
    
    // 拼接key 值,key为{serviceName}#{ip}#{port}
    public String buildKey(String dom, String ip, int port) {
        return dom + "#" + ip + "#" + port;
    }

    class BeatTask implements Runnable {
        BeatInfo beatInfo;

        public BeatTask(BeatInfo beatInfo) {
            this.beatInfo = beatInfo;
        }

        public void run() {
            Map<String, String> params = new HashMap(2);
            params.put("beat", JSON.toJSONString(this.beatInfo));
            params.put("dom", this.beatInfo.getDom());

            try {
                // 获取到 服务端的回应,这里找下去就是一个 http 请求
                String result = BeatReactor.this.serverProxy.callAllServers("/nacos/v1/ns/api/clientBeat", params);
                JSONObject jsonObject = JSON.parseObject(result);
                if (jsonObject != null) {
                    BeatReactor.this.clientBeatInterval = jsonObject.getLong("clientBeatInterval");
                }
            } catch (Exception var4) {
                LogUtils.LOG.error("CLIENT-BEAT", "failed to send beat: " + JSON.toJSONString(this.beatInfo), var4);
            }

        }
    }

    class BeatProcessor implements Runnable {
        BeatProcessor() {
        }

        public void run() {
            try {
                Iterator var1 = BeatReactor.this.dom2Beat.entrySet().iterator();

                while(var1.hasNext()) {
                    Entry<String, BeatInfo> entry = (Entry)var1.next();
                    BeatInfo beatInfo = (BeatInfo)entry.getValue();
                    // executor. schedule(Runnable command, long delay, TimeUnit unit)
                    // @param command the task to execute 进行调度的线程
                    // @param delay the time from now to delay execution 延迟时间
                    // @param unit the time unit of the delay parameter 时间单位(毫秒 MILLISECONDS 、微妙等)
                    // 发送心跳包
                    BeatReactor.this.executorService.schedule(BeatReactor.this.new BeatTask(beatInfo), 0L, TimeUnit.MILLISECONDS);
                    LogUtils.LOG.info("BEAT", "send beat to server: " + beatInfo.toString());
                }
            } catch (Exception var4) {
                LogUtils.LOG.error("CLIENT-BEAT", "Exception while scheduling beat.", var4);
            }

        }
    }
}

 
BeatReactor 在创建时启动了一个定时任务ScheduledExecutorService,
 
该定时任务主要工作就是不停的通过http请求发送心跳数据到Nacos服务端。
 


 
  a、向Nacos集群的随机一个节点的/v1/ns/api/clientBeat路径发送HTTP GET请求;
 
  b、从json响应中取出clientBeatInterval字段值更新BeatReactor的clientBeatInterval属性值。
 

 

  • 8、NamingProxy 类 源码分析 实现服务注册。
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package com.alibaba.nacos.client.naming.net;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.nacos.api.exception.NacosException;
import com.alibaba.nacos.api.naming.pojo.Instance;
import com.alibaba.nacos.api.naming.pojo.ListView;
import com.alibaba.nacos.client.naming.net.HttpClient.HttpResult;
import com.alibaba.nacos.client.naming.utils.CollectionUtils;
import com.alibaba.nacos.client.naming.utils.IoUtils;
import com.alibaba.nacos.client.naming.utils.LogUtils;
import com.alibaba.nacos.client.naming.utils.StringUtils;
import com.alibaba.nacos.common.util.UuidUtil;
import java.io.IOException;
import java.io.StringReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

public class NamingProxy {
    private static final int DEFAULT_SERVER_PORT = 8848;
    private String namespace;
    private String endpoint;
    private String nacosDomain;
    private List<String> serverList;
    private List<String> serversFromEndpoint = new ArrayList();
    private long lastSrvRefTime = 0L;
    private long vipSrvRefInterMillis;
    private ScheduledExecutorService executorService;

    public NamingProxy(String namespace, String endpoint, String serverList) {
        this.vipSrvRefInterMillis = TimeUnit.SECONDS.toMillis(30L);
        this.namespace = namespace;
        this.endpoint = endpoint;
        if (StringUtils.isNotEmpty(serverList)) {
            this.serverList = Arrays.asList(serverList.split(","));
            if (this.serverList.size() == 1) {
                this.nacosDomain = serverList;
            }
        }

        this.executorService = new ScheduledThreadPoolExecutor(1, new ThreadFactory() {
            public Thread newThread(Runnable r) {
                Thread t = new Thread(r);
                t.setName("com.alibaba.nacos.client.naming.serverlist.updater");
                t.setDaemon(true);
                return t;
            }
        });
        this.executorService.scheduleWithFixedDelay(new Runnable() {
            public void run() {
                NamingProxy.this.refreshSrvIfNeed();
            }
        }, 0L, this.vipSrvRefInterMillis, TimeUnit.MILLISECONDS);
        this.refreshSrvIfNeed();
    }
    
    // 此时接上面第 6 步 ,服务注册实现
    public void registerService(String serviceName, Instance instance) throws NacosException {
        LogUtils.LOG.info("REGISTER-SERVICE", "registering service " + serviceName + " with instance:" + instance);
        Map<String, String> params = new HashMap(8);
        params.put("tenant", this.namespace);
        params.put("ip", instance.getIp());
        params.put("port", String.valueOf(instance.getPort()));
        params.put("weight", String.valueOf(instance.getWeight()));
        params.put("enable", String.valueOf(instance.isEnabled()));
        params.put("healthy", String.valueOf(instance.isHealthy()));
        params.put("metadata", JSON.toJSONString(instance.getMetadata()));
        params.put("serviceName", serviceName);
        params.put("clusterName", instance.getClusterName());
        this.reqAPI("/nacos/v1/ns/instance", params, (String)"PUT");
    }
  
   // ……
   // 该类的源码在这里被省略部分方法,如需了解该类完整源码,可查看相关文档。
   // …… 


}

 
 
 
 
 
 
 
 
.

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Nacos是一个开源的动态服务发现、配置管理和服务管理平台。它提供了注册中心、配置中心和命名空间等功能。其中,Nacos注册中心实现原理如下: Nacos注册中心采用了Raft算法来保证数据的一致性和可靠性。Raft算法是一种分布式一致性算法,它将整个集群划分为多个节点,每个节点都有自己的状态和角色。在Nacos中,每个节点都可以成为Leader、Follower或Candidate。Leader节点负责处理客户端请求,Follower节点负责接收Leader节点的同步请求,Candidate节点则是准备竞选Leader的节点。 当一个服务实例启动时,它会向Nacos注册中心发送注册请求,注册中心会将该服务实例的信息存储在内存中,并将该信息同步给其他节点。当一个服务实例下线时,它会向Nacos注册中心发送注销请求,注册中心会将该服务实例的信息从内存中删除,并将该信息同步给其他节点。 除了服务实例的注册和注销,Nacos注册中心还支持服务实例的心跳检测服务实例的元数据管理等功能。服务实例的心跳检测可以保证注册中心能够及时发现服务实例的故障,而服务实例的元数据管理可以帮助用户更好地管理服务实例的信息。 总之,Nacos注册中心采用了Raft算法来保证数据的一致性和可靠性,同时支持服务实例的注册、注销、心跳检测和元数据管理等功能,从而实现了一个高可用、高可靠的服务注册中心

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值