SpringCloud源码学习笔记3——Nacos服务注册源码分析

这篇具有很好参考价值的文章主要介绍了SpringCloud源码学习笔记3——Nacos服务注册源码分析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

系列文章目录和关于我

一丶基本概念&Nacos架构

1.为什么需要注册中心

  • 实现服务治理、服务动态扩容,以及调用时能有负载均衡的效果。

    如果我们将服务提供方的ip地址配置在服务消费方的配置文件中,当服务提供方实例上线下线,消费方都需要重启服务,导致二者耦合度过高。注册中心就是在二者之间加一层,实现解耦合。

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

  • 健康检查和服务摘除:主动的检查服务健康情况,对于宕机的服务将其摘除服务列表

2.Nacos 的架构

  • Naming Service :注册中心,提供服务注册,注销,管理
  • Config Service:配置中心,Nacos 配置中心为服务配置提供了编辑、存储、分发、变更管理、历史版本管理等功能,并且支持在实例运行中,更改配置。
  • OpenAPI:nacos对外暴露的接口,Provider App(服务提供者)就是调用这里的接口,实现将自己注册到nacos,Consumer App(服务消费者)也是使用这里的接口拉去配置中心中的服务提供者的信息。

3.nacos数据模型

SpringCloud源码学习笔记3——Nacos服务注册源码分析

二丶nacos注册中心简单使用

我们使用nacos作为注册中心,只需要下载nacos提供的jar包并运行启动nacos服务,然后在服务提供者,消费者中引入spring-cloud-starter-alibaba-nacos-discovery,并配置spring.cloud.nacos.discovery.server-addr=nacos服务启动的地址,即可在nacos可视化界面看到:

SpringCloud源码学习笔记3——Nacos服务注册源码分析

那么服务是如何注册到nacos的昵?

三丶服务注册源码分析

当我们服务引入spring-cloud-starter-alibaba-nacos-discovery,便可以实现自动进行注册,这是因为在spring.facotries中自动装配了NacosServiceRegistryAutoConfiguration

SpringBoot源码学习1——SpringBoot自动装配源码解析+Spring如何处理配置类的

SpringCloud源码学习笔记3——Nacos服务注册源码分析

1.NacosServiceRegistryAutoConfiguration 引入了哪些类

点进NacosServiceRegistryAutoConfiguration 源码中,发现它注入了一下三个类

1.1.NacosServiceRegistry

SpringCloud源码学习笔记3——Nacos服务注册源码分析

SpringCloud源码学习笔记3——Nacos服务注册源码分析

  • ServiceInstance 表示的是服务发现中的一个实例

    这个接口定义了类似于getHost,getIp获取注册实例host,ip等方法,是springcloud定义的规范接口

  • Registration一个标记接口,ServiceRegistry<R>这里面的R泛型就是Registration

    是springcloud定义的规范接口

  • ServiceRegistry 服务注册,定义如何向注册中心进行注册,和取消注册

    这个接口定义了register服务注册,deregister服务取消注册等方法,入参是Registration。它是springcloud定义的规范接口。

spring cloud 定义了诸多规范接口,无论是服务注册,还是负载均衡,让其他中间件实现
  • NacosServiceRegistry nacos服务注册接口,实现了ServiceRegistry,定义了如何注册,如何取消注册,维护服务状态等。

1.2.NacosRegistration

SpringCloud源码学习笔记3——Nacos服务注册源码分析

SpringCloud源码学习笔记3——Nacos服务注册源码分析

NacosRegistrationRegistration的实现类,象征着一个Nacos注册中心的服务,也就是我们自己写的springboot服务

1.3.NacosAutoServiceRegistration

SpringCloud源码学习笔记3——Nacos服务注册源码分析

SpringCloud源码学习笔记3——Nacos服务注册源码分析

  • AutoServiceRegistration一个标记接口,表示当前类是一个自动服务注册类
  • AbstractAutoServiceRegistration 实现了ApplicationListener,监听WebServerInitializedEvent web服务初始化结束事件,在ApplicationListener#onApplicationEvent中进行服务注册
  • NacosAutoServiceRegistration使用NacosServiceRegistryNacosRegistration的注册到nacos注册中心

一通分析之后,可以看到NacosAutoServiceRegistration 是最核心的类,它负责监听事件,调用NacosServiceRegistry,将服务注册到注册中心。

2.AbstractAutoServiceRegistration 监听事件进行注册

此类是SpringCloud提供的模板类,让市面上众多注册中心中间件实现它,快速接入SpringCloud生态。

SpringCloud源码学习笔记3——Nacos服务注册源码分析

2.1 WebServerInitializedEvent 从何而来

AbstractAutoServiceRegistration想响应WebServerInitializedEvent ,那么WebServerInitializedEvent 是哪儿发出的昵?

WebServerStartStopLifecycle#start方法

SpringCloud源码学习笔记3——Nacos服务注册源码分析

SpringCloud源码学习笔记3——Nacos服务注册源码分析

WebServerStartStopLifecycle实现了Lifecycle,在spring容器刷新结束的时候,会使用LifecycleProcessor调用所以Lifecycle#start,从而发送ServletWebServerInitializedEvent(WebServerInitializedEvent子类)推送事件

Reactive的springboot上下文则是由WebServerStartStopLifecycle推送ReactiveWebServerInitializedEvent事件,原理一样,如下图

SpringCloud源码学习笔记3——Nacos服务注册源码分析

2.2 NacosAutoServiceRegistration如何进行服务注册

AbstractAutoServiceRegistration在响应事件后,会调用bind方法,进而调用register进行服务注册,这里就会调用到NacosAutoServiceRegistration#register

SpringCloud源码学习笔记3——Nacos服务注册源码分析

那么到底如何进行服务注册?

SpringCloud源码学习笔记3——Nacos服务注册源码分析

可以看到直接调用NacosServiceRegistry#register(NacosRegistration)进行服务注册

3.NacosServiceRegistry 服务注册

SpringCloud源码学习笔记3——Nacos服务注册源码分析

可以看到这里使用NamingServiceInstance进行注册

  • NamingService,nacos框架中的类,负责服务注册和取消注册
  • Instance,nacos框架中的类,定义一个服务,记录ip,端口等信息
可以看到nacos有自己一套东西,脱离springcloud,也可以使用,这就是松耦合

下面我们看下NamingService是如何进行服务注册的SpringCloud源码学习笔记3——Nacos服务注册源码分析

  • 如果是临时实例,会使用ScheduledThreadPoolExecutor,每5秒发送一次心跳,发送心跳即请求nacos注册中心/instance/beat接口

  • 然后调用NamingProxy 进行服务注册

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

    最终底层通过Http请求的方式,请求nacos服务的/nacos/v1/ns/instance

SpringCloud源码学习笔记3——Nacos服务注册源码分析

4.nacos注册中心如何处理服务注册的请求

上面一通分析,我们直到了springboot服务是如何启动的时候,自动进行服务注册的,如何进行服务注册的,但是nacos服务端是如何响应注册请求的的昵

SpringCloud源码学习笔记3——Nacos服务注册源码分析

  • 从请求中拿实例信息

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

    主要包含上述这些字段。

  • ServiceManager#registerInstance

    服务注册的逻辑主要在addInstance方法中

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

    首先根据待注册服务的namespaceId命名中间idserviceName服务名称ephemeral是否临时服务构建出一个key,由于我们是一个临时实例,key最终为com.alibaba.nacos.naming.iplist.ephemeral + namespaceId ## + serviceName

    然后调用ConsistencyService一致性协议服务#put进行注册,这里和Nacos支持AP,CP架构有关,后续我们分析到一致性协议再补充。

    这里会调用到DelegateConsistencyServiceImpl(一致性协议门面)他会根据key中的是临时实例,还是非临时实例,选择协议,最终选择到DistroConsistencyServiceImpl,继续调用put方法

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

    可以看到DistroConsistencyServiceImpl(Distro一致性协议服务)会同步到nacos集群中的其他实例,这部分我们后续分析,我们重点看下onPut,看看nacos服务到底如何注册。

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

    SpringCloud源码学习笔记3——Nacos服务注册源码分析

    至此服务注册请求结束了,只是将注册请求信息包装成了任务加入到Notifier的任务队列中。

5.nacos 服务注册表结构

在看怎么处理阻塞队列中的任务前,我们看下nacos的注册表结构

SpringCloud源码学习笔记3——Nacos服务注册源码分析

对应ServiceManager中的serviceMap属性

/**
 * key 是命名空间
 * value 是 分组名称和Service服务的map
 *
 */
private final Map<String, Map<String, Service>> serviceMap = new ConcurrentHashMap<>();

//Service结构如下
//集群和集群对象组成map
private Map<String, Cluster> clusterMap = new HashMap<>();

//Cluster 中的属性记录所有实例Instance的集合

6.nacos服务注册异步任务队列处理注册任务

上面分析到最终服务注册请求被包装放到Notifier的任务队列中。我们看下任务队列的任务在哪里被拿出来消费。

Notifier实现了Runnable,在DistroConsistencyServiceImpl中使用@PostConstruct将它提交到了调度线程池中。

SpringCloud源码学习笔记3——Nacos服务注册源码分析

也就是说会有一个单线程调用Notifier#run

SpringCloud源码学习笔记3——Nacos服务注册源码分析

SpringCloud源码学习笔记3——Nacos服务注册源码分析

后续会调用到Service#onChange,其updateIPs方法会更新实例的ip地址

// 这里 instances 里面就包含了新实例对象
// ephemeral 为 ture,临时实例
public void updateIPs(Collection<Instance> instances, boolean ephemeral) {

    // clusterMap 对应集群的Map
    Map<String, List<Instance>> ipMap = new HashMap<>(clusterMap.size());
    // 把集群名字都放入到ipMap里面,value是一个空的ArrayList
    for (String clusterName : clusterMap.keySet()) {
        ipMap.put(clusterName, new ArrayList<>());
    }

    // 遍历全部的Instance,这个List<Instance> 包含了之前已经注册过的实例,和新注册的实例对象
    // 这里的主要作用就是把相同集群下的 instance 进行分类
    for (Instance instance : instances) {
        try {
          
            // 判断客户端传过来的是 Instance 中,是否有设置 ClusterName
            if (StringUtils.isEmpty(instance.getClusterName())) {
                // 如果没有,就给ClusterName赋值为 DEFAULT
                instance.setClusterName(UtilsAndCommons.DEFAULT_CLUSTER_NAME);
            }

            // 判断之前是否存在对应的 ClusterName,如果没有则需要创建新的 Cluster 对象
            if (!clusterMap.containsKey(instance.getClusterName())) {
                // 创建新的集群对象
                Cluster cluster = new Cluster(instance.getClusterName(), this);
                cluster.init();
                // 放入到集群 clusterMap 当中
                getClusterMap().put(instance.getClusterName(), cluster);
            }

            // 通过集群名字,从 ipMap 里面取
            List<Instance> clusterIPs = ipMap.get(instance.getClusterName());
            // 只有是新创建集群名字,这里才会为空,之前老的集群名字,在方法一开始里面都 value 赋值了 new ArrayList对象
            if (clusterIPs == null) {
                clusterIPs = new LinkedList<>();
                ipMap.put(instance.getClusterName(), clusterIPs);
            }

            // 把对应集群下的instance,添加进去
            clusterIPs.add(instance);
        } catch (Exception e) {
        }
    }

    // 分好类之后,针对每一个 ClusterName ,写入到注册表中
    for (Map.Entry<String, List<Instance>> entry : ipMap.entrySet()) {
        // entryIPs 已经是根据ClusterName分好组的实例列表
        List<Instance> entryIPs = entry.getValue();
        
        // 对每一个 Cluster 对象修改注册表  ->updateIps
        clusterMap.get(entry.getKey()).updateIps(entryIPs, ephemeral);
    }

}

针对每一个集群分别进行Cluster#updateIps

public void updateIps(List<Instance> ips, boolean ephemeral) {

    // 先判断是否是临时实例
    // ephemeralInstances 临时实例
    // persistentInstances 持久化实例
    // 把对应数据先拿出来,放入到 新创建的 toUpdateInstances 集合中
    Set<Instance> toUpdateInstances = ephemeral ? ephemeralInstances : persistentInstances;

    // 先把老的实例列表复制一份 , 先复制一份新的
    //写时复制,先复制一份
    HashMap<String, Instance> oldIpMap = new HashMap<>(toUpdateInstances.size());
    for (Instance ip : toUpdateInstances) {
        oldIpMap.put(ip.getDatumKey(), ip);
    }

    //省略了同步到其他nacos服务的代码。。。
    
    // 最后把传入进来的实例列表,重新初始化一个 HaseSet,赋值给toUpdateInstances
    toUpdateInstances = new HashSet<>(ips);
    
    // 判断是否是临时实例
    if (ephemeral) {
        // 直接把之前的实例列表替换成新的
        ephemeralInstances = toUpdateInstances;
    } else {
        persistentInstances = toUpdateInstances;
    }
}

SpringCloud源码学习笔记3——Nacos服务注册源码分析文章来源地址https://www.toymoban.com/news/detail-404403.html

到了这里,关于SpringCloud源码学习笔记3——Nacos服务注册源码分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【SpringCloud】三、Nacos服务注册+配置管理+集群搭建

    官网:https://nacos.io/zh-cn/ 下载 解压 启动 启动成功 登录 在cloud-demo 父工程中添加 spring-cloud-alilbaba的管理依赖: 子模块下添加nacos的客户端依赖(此时user、order中的eureka可以注释掉了) 在order和user模块的application.yml文件中,注释eureka地址,添加nacos的地址 重启order服务,查看

    2024年02月06日
    浏览(54)
  • SpringCloud以及Nacos服务注册IP选择问题

    场景: 微服务部署后,需要相互调用,其中服务A调用服务B时发现无法调用。其中服务注册和发现以及配置中心使用Nacos 分析: 检查了多遍代码后,没有发现调用方式有问题,所以只能是网络问题。通过postman直接调用服务B,发现可以调通,但是使用服务A不行,于是检查服务

    2024年02月06日
    浏览(39)
  • SpringCloud微服务注册中心:Nacos介绍,微服务注册,Ribbon通信,Ribbon负载均衡,Nacos配置管理详细介绍

    注册中心可以说是微服务架构中的”通讯录“,它记录了服务和服务地址的映射关系。在分布式架构中,服务会注册到这里,当服务需要调用其它服务时,就这里找到服务的地址,进行调用。 服务注册中心(简称注册中心)是微服务框架的一个重要组件,在微服务架构里主要

    2024年02月22日
    浏览(63)
  • SpringCloud学习笔记(上):服务注册与发现:Eureka、Zookeeper、Consul+负载均衡服务调用:Ribbon

    SpringCloud=分布式微服务架构的一站式解决方案,是多种微服务架构落地技术的集合体,俗称微服务全家桶。 springboot版本选择: git源码地址:https://github.com/spring-projects/spring-boot/releases/ SpringBoot2.0新特性:https://github.com/spring-projects/spring-boot/wiki/Spring-Boot-2.0-Release springcloud版本选

    2024年02月08日
    浏览(43)
  • 【SpringCloud入门】-- Nacos快速入门之搭建服务与注册中心

    目录 前言:  1.Nacos的下载与安装 2. 去MySQL建立一个名为nacos的数据库 3.介绍配置文件,conf目录下的 application.properties 4.nacos启动 5. nacos作为注册中心的作用 6.建立一个项目,实现向命名空间注册 前言: 上文我们已经简单介绍了一下Nacos,现在我们一起来动手搭建一个Nacos的注

    2024年02月09日
    浏览(37)
  • 基于SpringCloud的微服务架构学习笔记(2)注册中心Eureka和负载均衡Ribbon

    1.7.1 远程调用的问题 地址信息获取 : 服务消费者 如何获取 服务提供者 的 地址信息 (不能每次都写死): URL:http://localhost:8081/user/\\\"+order.getUserId() 多选一 :如果有多个服务提供者,消费者如何进行选择 监测健康状态 :消费者如何获知提供者的健康状态 1.7.2 eureka原理 地址

    2024年02月13日
    浏览(36)
  • 手写SpringCloud系列-一分钟理解微服务注册中心(Nacos)原理。

    手写SpringCLoud项目地址,求个star github:https://github.com/huangjianguo2000/spring-cloud-lightweight gitee:https://gitee.com/huangjianguo2000/spring-cloud-lightweigh 1. 总结服务注册中心 我们可以理解注册中心就是一个HashMap,服务注册上去,需要用的时候去拉取,通过服务名称可以找到对应服务的IP地址和

    2024年02月14日
    浏览(44)
  • SpringCloud + Gateway(网关) + Nacos(注册中心+配置中心)+ Dubbo(内部服务调用)

    Apache Dubbo是一款微服务开发框架,它提供了 RPC通信 与 微服务治理 两大关键能力 1、协议支持方面 Feign更加优雅简单。Feign是通过REST API实现的远程调用,基于Http传输协议,服务提供者需要对外暴露Http接口供消费者调用,服务粒度是http接口级的。通过短连接的方式进行通信,

    2024年02月06日
    浏览(197)
  • SpringCloud使用nacos注册微服务,undertow为web服务器时,微服务下线问题

    服务下线时抛出异常: 出现错误原因:         由于服务下线时触发关闭Hook,undertow在nacos之前先关闭了,导致naocs取不到undertow里面的对象,导致空指针异常 处理方式:         1、这里导致服务无法下线,故可以重写这个 naocs 的 Hook         2、调整NacosWatch关闭顺序,在

    2024年02月11日
    浏览(42)
  • SpringCloud(H版&alibaba)框架开发教程,使用eureka,zookeeper,consul,nacos做注册中心——附源码(1)

    源码地址:https://gitee.com/jackXUYY/springboot-example 创建订单服务,支付服务,公共api服务(共用的实体),eureka服务 1.cloud-consumer-order80 2.cloud-provider-payment8001 3.cloud-api-commons 4.cloud-eureka-server7001 5.cloud-eureka-server7002 如图所示 修改本地host映射 修改数据库地址为自己的地址,并初始

    2024年02月03日
    浏览(47)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包