Nacos(全称为"Naming and Configuration Service")是一个开源的服务发现和配置管理平台。作为一个注册中心,Nacos提供了服务注册、服务发现、服务心跳和服务健康检测功能,使得微服务架构中的各个服务可以相互发现和通信。
本文将深入探讨Nacos注册中心的原理,特别关注CP模式与AP模式的区别与优劣
环境
版本:Nacos-1.3.0
我们知道一般组件与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进行分析
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);
//服务