深入剖析Spring Cloud源码系列Nacos注册中心原理新手面试考核问题

前言

Nacos(全称为"Naming and Configuration Service")是一个开源的服务发现和配置管理平台。作为一个注册中心,Nacos提供了服务注册、服务发现、服务心跳和服务健康检测功能,使得微服务架构中的各个服务可以相互发现和通信。

本文将深入探讨Nacos注册中心的原理,特别关注CP模式与AP模式的区别与优劣
环境

版本:Nacos-1.3.0

一、Nacos注册中心 与 Spring Cloud 整合

我们知道一般组件与spring cloud整合时,要去加载spring.factories,接下我们看看spring.factories文件都有些什么?

spring.factories

Nacos 服务注册自动装配 - NacosServiceRegistryAutoConfiguration

@Configuration
@EnableConfigurationProperties
@ConditionalOnNacosDiscoveryEnabled // 仅当启用Nacos的服务发现功能时才生效
@ConditionalOnProperty(value = "spring.cloud.service-registry.auto-registration.enabled",
        matchIfMissing = true) // 当未配置该属性时,默认为启用服务自动注册功能
@AutoConfigureAfter({
    AutoServiceRegistrationConfiguration.class,
        AutoServiceRegistrationAutoConfiguration.class,
        NacosDiscoveryAutoConfiguration.class }) // 在指定配置类之后,当前配置类自动配置
public class NacosServiceRegistryAutoConfiguration {
   

    @Bean
    public NacosServiceRegistry nacosServiceRegistry(
            NacosDiscoveryProperties nacosDiscoveryProperties) {
   
        return new NacosServiceRegistry(nacosDiscoveryProperties);
    }

    @Bean
    @ConditionalOnBean(AutoServiceRegistrationProperties.class)
    public NacosRegistration nacosRegistration(
            NacosDiscoveryProperties nacosDiscoveryProperties,
            ApplicationContext context) {
   
        return new NacosRegistration(nacosDiscoveryProperties, context);
    }

    @Bean
    @ConditionalOnBean(AutoServiceRegistrationProperties.class)
    public NacosAutoServiceRegistration nacosAutoServiceRegistration(
            NacosServiceRegistry registry,
            AutoServiceRegistrationProperties autoServiceRegistrationProperties,
            NacosRegistration registration) {
   
        return new NacosAutoServiceRegistration(registry,
                autoServiceRegistrationProperties, registration);
    }

}
NacosAutoServiceRegistration : 用于在 Spring Cloud 应用中自动触发(例如 订阅事件)将服务实例注册到 Nacos 服务注册中心
NacosServiceRegistry : 实现了 Spring Cloud Commons 中的 ServiceRegistry 接口的具体类,该接口是为注册中心提供统一API((门面模式) ,用于抽象不同注册中心的差异,无需关心底层注册中心的具体实现。

接下来,我们展开对NacosAutoServiceRegistration 、 NacosServiceRegistry进行分析

二、Nacos客户端-服务注册

NacosAutoServiceRegistration

//NacosAutoServiceRegistration 继承了AbstractAutoServiceRegistration
//先看看AbstractAutoServiceRegistration
public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration> {
   

    ...省略
}

/**
 * AbstractAutoServiceRegistration 是服务自动注册的抽象类
 * 继承了ApplicationListener 接口
 * 用于监听 Web 服务器初始化事件和获取 Spring 应用程序上下文。
 *
 * @param  服务注册的具体类型,继承 Registration 接口
 */
public abstract class AbstractAutoServiceRegistration<R extends Registration>
        implements AutoServiceRegistration, ApplicationContextAware, ApplicationListener<WebServerInitializedEvent> {
   
    ...省略

    @Override
    @SuppressWarnings("deprecation")
    public void onApplicationEvent(WebServerInitializedEvent event) {
   
        //1.处理 Web 服务器初始化事件,委派给 bind 方法处理
        bind(event);
    }

    public void bind(WebServerInitializedEvent event) {
   
        ApplicationContext context = event.getApplicationContext();
        if (context instanceof ConfigurableWebServerApplicationContext) {
   
            if ("management".equals(((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {
   
                return;
            }
        }
        //在应用上下文中获取 Web 服务器的端口号并调用 start 方法
        this.port.compareAndSet(0, event.getWebServer().getPort());
        //2. 启动服务自动注册过程
        this.start();
    }

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

        // 只有在非安全端口大于0且服务未运行时才初始化
        if (!this.running.get()) {
   
            //发布前置注册事件
            this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));
            //3. 调用子类钩子
            register();
            if (shouldRegisterManagement()) {
   
                registerManagement();
            }
            //发布后置注册事件
            this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));
            //变更运行状态
            this.running.compareAndSet(false, true);
        }
    }

    protected void register() {
   
        //5. 注册服务实例到服务注册中心
        this.serviceRegistry.register(getRegistration());
    }

    //...省略
}

public class NacosAutoServiceRegistration extends AbstractAutoServiceRegistration<Registration> {
   

    ...省略

    /**
     * 重写模板父类的钩子 register 方法,执行服务注册的逻辑。
     */
    @Override
    protected void register() {
   
        // 检查注册是否被禁用
        if (!this.registration.getNacosDiscoveryProperties().isRegisterEnabled()) {
   
            log.debug("Registration disabled.");
            return;
        }
        // 如果服务实例的端口号小于0,则将端口号设置为当前获取到的端口号
        if (this.registration.getPort() < 0) {
   
            this.registration.setPort(getPort().get());
        }
        // 4. 调用父类的 register 方法,实现服务注册
        super.register();
    }
}

在这里,在Nacos注册中心使用AbstractAutoServiceRegistration来监听WebServerInitializedEvent事件。

当Spring核心逻辑执行完成刷新(finishRefresh())时,会发布WebServerInitializedEvent事件。此事件由AbstractAutoServiceRegistration的onApplicationEvent方法响应,从而启动服务的自动注册流程。

具体实现是通过NacosAutoServiceRegistration#register()方法来进行前置参数检查,并最终调用NacosServiceRegistry#register()方法来实现服务的注册。

接下来,我们将深入探究NacosServiceRegistry的服务注册实现。

在AbstractAutoServiceRegistration 中定义了start()方法作为模板方法,用于定制服务自动注册的整体流程。具体的实现类(如NacosAutoServiceRegistration)则可以通过重写register()方法来添加自定义的逻辑,从而实现钩子(hook)功能,将自定义逻辑插入到服务自动注册的流程中。

NacosServiceRegistry分析

/**
 * NacosServiceRegistry 是 Nacos 服务注册中心的实现类,实现了 ServiceRegistry 接口。
 */
public class NacosServiceRegistry implements ServiceRegistry<Registration> {
   

    private final NacosDiscoveryProperties nacosDiscoveryProperties; //Nacos 服务发现属性

    private final NamingService namingService; //Nacos网络通信服务

    public NacosServiceRegistry(NacosDiscoveryProperties nacosDiscoveryProperties) {
   
        this.nacosDiscoveryProperties = nacosDiscoveryProperties;
        //通过NacosFatory工厂创建NacosNamingService网络通信
        this.namingService = nacosDiscoveryProperties.namingServiceInstance();
    }

    /**
     * 注册服务实例到 Nacos 服务注册中心。
     */
    @Override
    public void register(Registration registration) {
   

        ...省略

        String serviceId = registration.getServiceId();
        String group = nacosDiscoveryProperties.getGroup();

        // 封装服务实例信息
        Instance instance = getNacosInstanceFromRegistration(registration);

        try {
   
            // 调用 Nacos 的 API 注册服务实例
            namingService.registerInstance(serviceId, group, instance);

        } catch (Exception e) {
   
            log.error("Nacos registry, {} register failed...{},", serviceId,
                    registration.toString(), e);
            // issue : https://github.com/alibaba/spring-cloud-alibaba/issues/1132
            rethrowRuntimeException(e);
        }
    }

    //服务实例注销
    @Override
    public void deregister(Registration registration) {
   
        // 省略具体实现;
    }

    @Override
    public void close() {
   
        // 这里可以添加一些关闭资源的逻辑
    }

    //设置服务实例的状态。
    @Override
    public void setStatus(Registration registration, String status) {
   
        // 省略具体实现
    }

    //获取服务实例的状态。
    @Override
    public Object getStatus(Registration registration) {
   
        // 省略具体实现
        return null;
    }
}

//spring could 提供统一接口功能的门面模式
public interface ServiceRegistry<R extends Registration> {
   

    //服务实例注册
    void register(R registration);

    //服务

你可能感兴趣的:(spring,cloud,面试,spring)