Nacos服务注册原理分析

在分布式服务中,原来的单体服务会被拆分成一个个微服务,服务注册实例到注册中心,服务消费者通过注册中心获取实例列表,直接请求调用服务 。

Nacos服务注册原理分析

文章插图
 
服务是如何注册到注册中心,服务如果挂了,服务是如何检测?带着这些问题,我们从源码上对服务注册进行简单的源码分析 。
版本 2.1.1
  • Nacos Server:2.1.1
  • spring-cloud-starter-alibaba:2.1.1.RELEASE
  • spring-boot:2.1.1.RELEASE
方便统一版本,客户端和服务端版本号都为2.1.1 。
客户端启动nacos服务注册和发现需要添加maven依赖:
<dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>${latest.version}</version></dependency>根据maven依赖找到对应的spring.factories文件:
Nacos服务注册原理分析

文章插图
 
在spring.factories文件里找到启动配置类信息,SpringBoot服务启动时会将这些配置类信息注入到bean容器中 。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.alibaba.cloud.nacos.NacosDiscoveryAutoConfiguration,com.alibaba.cloud.nacos.ribbon.RibbonNacosAutoConfiguration,com.alibaba.cloud.nacos.endpoint.NacosDiscoveryEndpointAutoConfiguration,com.alibaba.cloud.nacos.discovery.NacosDiscoveryClientAutoConfiguration,com.alibaba.cloud.nacos.discovery.configclient.NacosConfigServerAutoConfigurationorg.springframework.cloud.bootstrap.BootstrapConfiguration=com.alibaba.cloud.nacos.discovery.configclient.NacosDiscoveryClientConfigServiceBootstrapConfiguration服务注册的核心配置类为:NacosDiscoveryAutoConfiguration,该类配置三个bean对象:
  • NacosServiceRegistry
  • NacosRegistration
  • NacosAutoServiceRegistration
NacosAutoServiceRegistrationNacosAutoServiceRegistration继承了抽象类AbstractAutoServiceRegistration 。AbstractAutoServiceRegistration抽象类又实现了ApplicationListener接口 。
实现ApplicationListener接口的方法,会在Spring容器初始化完成之后调用onApplicationEvent方法:
public void onApplicationEvent(WebServerInitializedEvent event) {bind(event);}调用bind方法:
public void bind(WebServerInitializedEvent event) {ApplicationContext context = event.getApplicationContext();if (context instanceof ConfigurableWebServerApplicationContext) {if ("management".equals(((ConfigurableWebServerApplicationContext) context).getServerNamespace())) {return;}}this.port.compareAndSet(0, event.getWebServer().getPort());// 调用 start 方法this.start(); }调用了start方法:
public void start() {if (!isEnabled()) {if (logger.isDebugEnabled()) {logger.debug("Discovery Lifecycle disabled. Not starting");}return;}if (!this.running.get()) {this.context.publishEvent(new InstancePreRegisteredEvent(this, getRegistration()));register();if (shouldRegisterManagement()) {registerManagement();}this.context.publishEvent(new InstanceRegisteredEvent<>(this, getConfiguration()));this.running.compareAndSet(false, true);}}调用了register方法,最终调用的是NacosServiceRegistry类的register方法 。
NacosServiceRegistry根据上文可知,服务器启动后调用NacosServiceRegistry类的register方法,该方法实现将实例注册到服务端:
public void register(Registration registration) {if (StringUtils.isEmpty(registration.getServiceId())) {log.warn("No service to register for nacos client...");return;}String serviceId = registration.getServiceId();String group = nacosDiscoveryProperties.getGroup();// 创建实例Instance instance = getNacosInstanceFromRegistration(registration);try {// 注册实例namingService.registerInstance(serviceId, group, instance);log.info("nacos registry, {} {} {}:{} register finished", group, serviceId,instance.getIp(), instance.getPort());}catch (Exception e) {log.error("nacos registry, {} register failed...{},", serviceId,registration.toString(), e);}}创建实例,然后通过namingService.registerInstance方法注册实例,然后查看registerInstance方法:
@Overridepublic void registerInstance(String serviceName, String groupName, Instance instance) throws NacosException {if (instance.isEphemeral()) {// 封装心跳包BeatInfo beatInfo = new BeatInfo();beatInfo.setServiceName(NamingUtils.getGroupedName(serviceName, groupName));beatInfo.setIp(instance.getIp());beatInfo.setPort(instance.getPort());beatInfo.setCluster(instance.getClusterName());beatInfo.setWeight(instance.getWeight());beatInfo.setMetadata(instance.getMetadata());beatInfo.setScheduled(false);long instanceInterval = instance.getInstanceHeartBeatInterval();beatInfo.setPeriod(instanceInterval == 0 ? DEFAULT_HEART_BEAT_INTERVAL : instanceInterval);// 发送心跳包beatReactor.addBeatInfo(NamingUtils.getGroupedName(serviceName, groupName), beatInfo);}// 发送实例serverProxy.registerService(NamingUtils.getGroupedName(serviceName, groupName), groupName, instance);}


推荐阅读