2、nacos 2.1.0注册中心原理及源码分析

news2024/11/19 7:28:45

一、为什么有这课程

Spring Cloud Alibaba 新版本中Seata 1.5.2和Nacos 2.1.0 在性能和使用方面都有很大提升,这节课将从使用和源码的角度详细讲解这两个框架。

二、设计注册中心

1、分布式框架的注意点:三高架构

  • 高可用

    高可用性(High Availability)通常来描述一个系统经过专门的设计,从而减少停工时间,而保持其服务的高度可用性(一直都能用)。

    解决方案:集群

  • 高并发

    高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。 高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。

    解决方案:

    • 垂直扩展增强单机硬件性能
    • 水平扩展
  • 高性能

    高性能(High Performance)就是指程序处理速度快,所占内存少,cpu占用率低

    解决方案:

    指程序处理速度快: 这里设计我们数据存储结构、访问机制、集群同步

2、注册中心的设计

image.png

  • 服务注册
  • 注册表结构设计
  • 服务发现
  • 服务订阅
  • 服务推送
  • 健康检查
  • 集群同步:设计到数据同步,数据同步我们有哪些协议 raft 、distro、ZAB

三、Nacos作为注册中心源码分析

1、项目准备

  • 客户端项目:msbshop-parent
    注意版本的对应

    image.png

  • 服务端项目:nacos-2.1.0

    下载对应的nacos,进行编译

    mvn clean install -DskipTests -Drat.skip=true -f pom.xml
    
  • 启动源码服务时候指定参数

    image.png

2、服务启动入口

2.1 整体流程图

image.png

2.2 源码分析

通过学习Nacos1.4 我们知道了我们的注册对应的类是NacosNamingService,那我们Nacos2.1.0是不是也是一样的呢?

image.png

通过上图我们发现里面也有注册的信息,那我们打上断点看一下是否到这里,我们在对应注册方法打上断点,然后debug启动,如图 :

image.png

我们发现服务启动后他确实通过这里,所以这里是注入的入口,那他是从哪里来这里的呢?

我们想nacos是和Springboot整合,那可能使用了SpringBoot的自动装配

我们查看我们引入的Jar包spring-cloud-starter-alibaba-nacos-discovery.jar 查看里面spring.factoris文件

image.png

我们可以查看自动装配类,在这里我们可以通过名称来推断那个关于注册自动配置类,NacosServiceRegistryAutoConfiguration应该和我们注册相关,我们进入看一下,导入以下类

image.png

我们可以通过上面debug端点看一下堆栈信息,看涉及到那个类

image.png

他的默认实现类是NacosAutoServiceRegistration

NacosAutoServiceRegistration 实现了ApplicationListener接口,监听事件WebServerInitializedEvent(spring核心方法refresh的完成后广播事件)

2.3 总结

找入口的方式:自动装配类 spring.factories

事件驱动:NacosAutoServiceRegistration实现了applicationListener接口

3、实例注册

3.1 整体流程图

image.png

3.2 客户端

3.2.1 源码分析

image.png

image.png

我们的初始化代码如下:

image.png

image.png

image.png

上面是通过实例的参数ephemeral值来判断是否是grpcClientProxy还是httpClientProxy,我们在他的实例化的位置能判断ephemeral的值

我们根据堆栈信息去看找到instance实例化的位置

image.png

具体实例创建

image.png

分析NacosDiscoveryPropertiesimage.png

image.png

由此我们知道这里使用grpc客户端端和服务端通信,同时我们能得出结论:我们

image.png

grpcClientProxy的调用

image.png

image.png

image.png

3.2.2 源码总结
  • 判断变量 1、 debug 2、 全文搜索 定位赋值位置
  • 通过ephemeral的值判断是grpc通信,还是http通信,通过这我们能判断ap模式是用的grpc模式,cp模式是用http通信
  • 判断服务端处理类的方式,我们可以根据请求参数,找对应服务端的处理类(由于开源框架都是规范的,一般都是根据请求参数来命名,所以可以采用这种方式)

3.3 服务端

image.png

3.3.1源码分析

image.png

这里我们注意我们实际注册的应该是对应的实例,而不是服务,服务包括多个实例,具体上的实例才有对应的ip和port

image.png

image.png

image.png

image.png

问题:这里一个服务对应一个实例,我们知道一个服务应该对应多个实例,为什么这里对应一个实例呢? 他是怎样处理的?后面我们进行解答

对事件ClientRegisterServiceEvent的监听,我们可以通过全文搜索来看,哪里对应的处理的

image.png下面进行事件监听进行处理:

image.png

image.png

publisherIndexs就是注册表

3.3.2 源码总结
  1. 分清实例和服务的关系: 我们实际注册的是实例 ,一个服务包含多个实例
  2. 这里注册实例会注册到我们Client中,Client有个Map,key:是service value是对应的一个实例,也就是一个Client对应一个服务的具体实例
  3. 我们发送事件后来处理注册表,注册表结构是ConcurrentMap<Service, Set<String>> publisherIndexes
    里面key:是服务,value对应Client的clientId

4、注册表

4.1 注册表结构分析

下面是我们nacos2.1.0的注册表

image.png

这里是Nacos1.4x的注册表

image.png

4.2 总结

通过Nacos1.4 和Nacos2.1 版本的注册表结构会发现,1.4 比较复杂,而2.1是比较简单,这样2.1的加锁的地方要少一些,所以2.1的注册表的结构性能要好,所以说我们可以总结一下,Nacoa2.1比Nacos1.4性能好的原因:

  1. Nacos2.1 使用的是GRPC性能要好一些
  2. Nacos2.1 表结构简单,所以加锁的地方要少一些,性能更好一些

5、服务发现

5.1 客户端

image.png

5.1.1 源码分析

我们需要从客户端找到服务发现的入口,我们注册的入口类是NacosNamingService,那我们服务发现入口应该也在这里:我们看一下有两个方法:getAllInstances和selectInstances

image.png

image.png

那具体是那个方法,我们可以在每个方法里面打上断点,然后debug启动后,进行访问

image.png

image.png

发送请求

image.png

image.png

从上图可以判断他是通过selectInstances来获取数据的

我们通过堆栈信息我们能发现,他的调用路径是通过ribbon最终调用selectInstances方法。

image.png

image.png

key1: 从缓存中获取数据

image.png

这里注意,他是从缓存中获取数据,那他一定有定时任务处理这里的数据,否则他就会有脏数据的问题,带着这个问题我们继续学习。

key2:进行订阅

我们服务启动第一次一定是空的,所以我们进行订阅,当定于的clientProxy,具体是那个值呢?

image.png

我们能确定clientProxy的具体实现类是NamingClientProxyDelegate,好我们看一下具体

image.png

key1:定时任务

image.png

这里的UpdateTask一定是个Runable,所以我们看他的run方法

image.png

image.png

总结上图内容:从缓存获取,如果没有则发送请求获取,如果有则判断数据是否超时,在finally里面对应的内容是这个任务每6秒执行一次,如果失败就会扩大两倍时长,最大是一分钟

里面更新缓存中内容如下:

image.png

这里先写内存后写磁盘,那磁盘数据什么时候获取呢?

我们在ServiceInfoHolder构造方法中发现?

image.png

那我们看一下服务发现对应代码

image.png

image.png

image.png

5.1.2 源码总结

  • 服务启动时候读取磁盘中数据放到缓存
  • 读取磁盘数据 如果没有则发送请求获取数据,然后写到缓存
  • 读取磁盘数据,如果有则判断时间是否过期,过期则发送请求,写到缓存
  • 读取数据是一个定时任务每6秒执行一次,如果失败就会延长,但最大时长是1分钟

5.2 服务端

image.png

5.2.1 源码分析

从上文中我们可以分析出我们服务端处理类应该是ServiceQueryRequestHandler

image.png

image.png

image.png

从上图可知getAllInstancesFromIndex是重点,它是获取我们对应的实例,来我们重点分析一下:

image.png

1、获取对应的clientId,这一定是在我们的注册表中获取的,注册表示个Map ,key:是服务名称,value:是对应client的set ,不理解的可以参考一下我们的注册表

image.png

2、获取对应实例这里我们详细看一下

image.png

这里可以和我们注册表中内容详细看一下

5.2.2 源码总结

这里主要是从注册表中获取数据,所以理解这里需要看一下我们的注册表中,各个数据之间的关系

6、服务订阅

6.1 客户端源码

image.png

源码可以参考我们服务发现对应的源码

image.png

image.png

image.png

6.2 服务端源码

image.png

6.2.1源码分析

image.png

key3: 查询服务列表的信息中,会调用serviceStorage.getData(service) 来获取服务的实例,这个和我们服务发现的服务端源码是一样的,这里就不在重复

key4:进行订阅

image.png

key2:把订阅者和服务进行关系绑定

image.png

image.png

这里和注册相同,每个客户端对应一个Map,Map里面key:是服务 value:就是这个服务对应的实例

key3:发送订阅事件, 我们全文搜索ClientSubscribeServiceEvent 查看处理事件位置

image.png

image.png

更新订阅表

image.png

6.2.2 源码总结

我们的订阅很简单首先是获取对应订阅这个服务的实例,用于返回,然后进行订阅,订阅的信息是我们对应发起定于服务者和被订阅服务会以map形式放到我们的client,然后发送一个事件,这个时间就是更新我们的订阅注册表

image.png

7、服务变更推送

这里注意我们推送有两种一种是服务变更推送,一种是订阅推送

服务变更推送:对于一个服务来说,订阅者有好多,我们在订阅表中能看到ConcurrentMap<Service, Set<String>> subscriberIndexes,能获所有订阅者,然后进行推送

订阅者推送:此时服务已经稳定,我这里增加一个msb-order,那对于msb-stock又增加一个订阅者,此时我们应该将msb-stock对应的实例推送给具体新增的实例

7.1 订阅推送

image.png

7.2.1服务端源码分析

客户端在订阅的时候发送事件更改注册表后,会再发送一个事件,这个事件就会获取对应的服务实例,然后通知订阅者获取对应的服务的实例,这里和上面我们直接订阅返回对应数据有点重复,这里我们可以注意一下,接下来我们看一下源码。

image.png

全文搜索ServiceSubscribedEvent查看处理事件的地方

image.png

image.png

我们进入addTask方法

image.png

我们想这里先从map中获取如果有则合并,没有则放进去,那我们想一定有个地方从这里来获取这个任务来处理;

我们看一下这个类的构造方法

image.png

这里有个定时任务来处理我们看一下

image.png

我们进入处理任务

image.png

这里的processor.process的处理方法

image.png

我们分析一下上面到底是那个方法,1、我们可以通过debug 2、我们可以猜测,我们想我们处理的任务是PushDelayTask ,所以我们用它PushDelayTask来搜索一下

image.png

所以处理类应该是PushDelayTaskProcessor

image.png

PushExecuteTask是实现Runable的线程,那重点应该是他的run方法

image.png

进入对应的run方法

image.png

key1:获取订阅这个服务的客户端ID

image.png

上面是判断是否是全部推送,如果我们有指定的ClientId就不全部推送,如果没有我们就全部推送,我们这是订阅推送,所以有要推送的客户端

key2:进行任务处理

image.png

image.png

image.png

image.png

7.2.2 客户端源码分析

服务端发送请求参数是ServerRequest,那我们怎样在客户端找到对应的处理方法呢? 还是老办法,用ServerRequest在客户端进行搜索

image.png

这个ServerRequestHandler是个接口,我们找他的实现类,如下

image.png

那具体的实现类,我们推理可以知道他一定是NamingPushRequestHandler

好我们来分析一下NamingPushRequestHandler

image.png

7.2.3 总结

我们新增服务订阅在更新完注册表会发布一个事件ServiceSubscribedEvent,NamingSubscriberServiceV2Impl.会监听事件,然后把订阅到的数据进行推送过去,这期间真正的工作任务是PushExecuteTask他是一个线程,同时注意这里是订阅,所以我们推送的时候,直接推送给新增订阅者就可以

7.2 服务变更推送

服务变更推送和订阅推送是一样的只是推送的对象不同,我们订阅推送是给新增订阅者进行推送,服务变更推送是给所有订阅这个服务的推送

image.png

image.png

8、心跳机制

image.png

8.1 源码分析

我们进入ConnectionManager里面的start方法中,这个方法上有@PostConstruct,也就是构造方法执行完毕就执行这个方法

image.png

上图中我们可以知道它里面线程是每3秒执行一次:

由于里面方法比较多,这里我们可以看一些关键的点:

image.png

image.pngimage.png

image.png

key5:注销

image.png

image.png

image.png

image.png

发布事件ClientDisconnectEvent

image.png

image.png

image.png

image.png

8.2 总结

image.png

9、数据同步

image.png

9.1 源码分析

我们在实例注册的时候就应该进行集群同步

image.png

全文搜索ClientChangedEvent查看哪里处理

image.png

image.png

image.png

image.png

image.png

我们进入addTask方法

image.png

进入NacosDelayTaskExecuteEngine的构造方法里面,启动一个定时任务ProcessRunnable

image.png

查看ProcessRunnable的run方法

image.png

image.png

我们处理的任务是DistroDelayTask ,所以说我们查看具体方法如下

image.png

image.png

image.png

DistroSyncChangeTask是具体的任务我看一下他的run方法

image.png

image.png

image.png

处理集群同步

从上图中我们知道集群同步的请求是DistroDataRequest, 那我可以在服务端全文搜索

image.png

处理数据同步

image.png

image.png

image.png

image.png

新增实例

image.png

image.png

9.2 总结

这里集群同步时候,我们采用的异步处理,这里和我们服务变更推送类似

10、GRPC源码分析

image.png

10.1、客户端源码分析

我们找到客户端注册的代码:

image.png

image.png

通过他初始化实例,我们知道他他真正的调用方法

image.png

通过方法getExecuteClientProxy需要确定具体代理类 grpcClientProxy

image.png

我们查找grpcClientProxy的初始化的地方。

image.png

那NamingGrpcClientProxy应该grpc的核心逻辑

image.png

我们进入start方法:

image.png

上面方法分为两部分:

key1:是将处理的Handler放到对应的List serverRequestHandlers 那后面一定是在客户端处理请求的时候,从哪这里面拿到对应的Handler进行处理

image.png

key2: 启动这里 这里是关键,我们进来看一下:

image.png

image.png

上图是简单描述:我们可以看一下第4、5、6、7步

key4:选择一个服务

image.png

image.png

key5:连接服务

image.png

key6: 发送事件到队列, 我们可以全文搜索哪里处理这个队列

线程池里面的一个线程正在处理,如

image.png

image.png

image.png

image.png

image.png

key7:

如果前面同步连接都失败的话,我们就进行异步连接

image.png

我们全文搜索就会发现在上文中的第二个线程中会进行处理

image.png

image.png

image.png

总结:在连接成功还是连接失败后都是异步进行处理,我们可以参考这种方式

10.2、服务端源码分析

image.png

服务处理rpc的请求,那我们可以进行猜测一下服务端进行搜索RpcServer,如下

image.png

那BaseRpcServer应该是处理RPC的请求,我们看一下对应代码

image.png

通过名称我们应该知道他是启动server,那我们查看哪里调用他

image.png

通过上图我们知道,他是构造方法之后我们进行服务启动

image.png

key1: 增加拦截器 ,这里主要获取一些远端Ip+port信息

image.png

key2: 这里面重点是建立连接和处理请求

image.png

key2.1 处理请求

我们想我们Springmvc处理请求的时候,我们是根据路径判断对应的controller,这里我们的请求应该是那个具体的handler呢? 我们是根据type,这个type其实就是请求类型

如下图:获取对应type ,然后根据type获取对应的的RequestHandler

image.png

我们进入getByRequestType

image.png

image.png从上图我们知道这里是将相应handler以map的形式进行存放,那这个key我们通过debug知道他对应的值,为请求参数的的名称

那什么时候进行初始化的:

image.png

image.png

那Handler对应泛型的第一参数类型名称是什么,那我们拿InstanceRequestHandler来举例:也就是InstanceRequest

image.png

总结:我们处理实例就是用的监听器来获取对应的所有实例,然后以map处理,所有请求从这map中拿取对应的对象。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/791245.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

智慧园区智能照明控制系统解决方案

1、概述 园区照明比较复杂&#xff0c;办公建筑、生产车间和园区道路、景观照明等类型比较多&#xff0c;而且对照明控制方式要求不一样。所以合理使用照明控制系统&#xff0c;针对不同建筑不同场景使用不同的控制策略&#xff0c;大程度使用自然光照明达到节省照明用电&#…

科技资讯|苹果开放Vision Pro头显开发套件申请,此前曝光三款电池

苹果今天宣布面向开发人员&#xff0c;正式接受 Vision Pro 头显开发套件申请&#xff0c;从而帮助其开发和测试应用程序。 苹果官方页面介绍&#xff0c;开发人员在获得 Vision Pro 头显开发套件之外&#xff0c;还可以获得设备设置和入门方面的帮助&#xff0c;与 Apple 专…

谷粒商城篇章5 ---- P173-P192 ---- 检索服务【分布式高级篇二】

目录 1 检索服务 1.1 搭建页面环境 1.1.1 引入依赖 1.1.2 将检索页面放到gulimall-search的src/main/resources/templates/目录下 1.1.3 调整搜索页面 1.1.4 将静态资源放到linux的nginx相关映射目录下/root/docker/nginx/html/static/ search/ 1.1.5 SwitchHosts配置域…

F5产品队列再添“猛将”,稳健守护云原生基础设施

提到F5产品队列&#xff0c;无论是负载均衡&#xff0c;还是独立部署且一次性购买的硬件产品&#xff0c;或者是F5 分布式云服务组合产品&#xff0c;都体现出F5的能力与能量。前不久&#xff0c;F5宣布推出云工作负载防护解决方案——F5 分布式云应用基础设施防护&#xff08;…

Python基础语法第六章之字典

一、字典 1.1字典是什么 字典是一种存储 键值对 的结构. 啥是键值对? 这是计算机/生活中一个非常广泛使用的概念. 把 键(key) 和 值(value) 进行一个一对一的映射, 然后就可以根据键, 快速找到值. 1.2创建字典 创建一个空的字典. 使用 { } 表示字典. a { } b dict() pr…

Win10从安全模式命令行退出安全模式正常启动

前两天听信他人的一则妖言&#xff0c;将windows设置为安全模式卸载软件&#xff0c;结果初始帐户密码忘记&#xff0c;登陆不了了&#xff0c;琢磨半天才正常启动用pin登录了系统。 微软可以使用本地帐户或在线帐户管理计算机&#xff0c;在线帐户的好处就是可以云同步密钥 设…

uniapp 微信小程序 预览pdf方法

效果图&#xff1a; 1、在小程序中 // #ifdef MP */ 是区分运行的环境&#xff0c;在小程序中可使用如下方法uni.downloadFile({url: item.link,//文件地址success: function (res) {var filePath res.tempFilePath;uni.openDocument({filePath: filePath,showMenu: false…

Hadoop学习日记-MapReduce思想及执行流程

MapReduce思想 Map负责“拆分”&#xff1a;即将复杂问题拆分成可以并行计算的小问题&#xff0c;彼此之间几乎没有依赖联系。 Reduce负责对Map阶段的结果进行合并汇总 Map和Reduce的抽象接口如下&#xff1a; map:(k1; v1) — (k2; v2) reduce:(k2; [v2]) — (k3; v3) 一…

行为型模式 - 解释器模式

概述 如上图&#xff0c;设计一个软件用来进行加减计算。我们第一想法就是使用工具类&#xff0c;提供对应的加法和减法的工具方法。 //用于两个整数相加 public static int add(int a,int b){return a b; }//用于两个整数相加 public static int add(int a,int b,int c){r…

玩转代码|JS实现中文字符串对utf-8的Base64编码的方法

目录 UTF-8 字符串编解码 解决方法 解析 utf8_to_b64 b64_to_utf8 弃用 unescape 和 escape 方法 原由 解决方法 Node.js 下的 Base64 编解码 Base64 编解码 Base64是一种使用64基的位置计数法。它使用2的最大次方来代表仅可打印的ASCII 字符。这使它可用来作为电子邮…

YOLOv2论文对比总结

1、高分辨率图片效果提升 2、Anchor 3、Loss函数 4、小目标友好

【文献分享】比目前最先进的模型轻30%!高效多机器人SLAM蒸馏描述符!

论文题目&#xff1a;Descriptor Distillation for Efficient Multi-Robot SLAM 中文题目&#xff1a;高效多机器人SLAM蒸馏描述符 作者&#xff1a;Xiyue Guo, Junjie Hu, Hujun Bao and Guofeng Zhang 作者机构&#xff1a;浙江大学CAD&CG国家重点实验室 香港中文大学…

Windows安装Redis(配置开机自启+配置密码)

Windows安装Redis 背景安装配置开机自启补充: 在Windows中配置jar自启动 设置密码暂时永久(推荐) 背景 Redis以其优异的性能备受青睐. 成为开发人员离不开的软件一直, 相信愿意点开观看此文的人DDDD 最近因为需要在Windows服务器上面搭建各种项目运行环境, 其中就包括Redis 因…

vue 实现课程表甘特图

1 封装 components <template><view style"padding-bottom: 100rpx;"><view class"header flex_sb"><div class"header_list flex" v-for"(item,index) in timeList" :key"item.value"><div&g…

CORS跨域资源共享漏洞

前置知识 跨域 域&#xff08;Domain&#xff09;是由三部分组成的标识&#xff1a;协议、域名和端口。 例如这两个ip就属于不同的域&#xff1a; http://example.com https://example.com 因为它们的协议不同&#xff08;一个是HTTP&#xff0c;另一个是HTTPS&#xff0…

2023百强县名单出炉!千亿县达54个

作为国民经济发展中的基本单元&#xff0c;县域经济发挥着重要作用。 赛迪顾问25日发布的《2023中国县域经济百强研究》&#xff08;下称“报告”&#xff09;显示&#xff0c;千亿县达54个&#xff0c;百强县前10名中江苏省独占6席。 在百强县前10名中&#xff0c;江苏省占席最…

Esp32_Arduino接入腾讯云笔记

ESP32是一款由乐鑫科技&#xff08;Espressif Systems&#xff09;推出的双核、低功耗、集成Wi-Fi和蓝牙的单芯片微控制器。它采用了Tensilica Xtensa LX6高性能处理器&#xff0c;具有大量的GPIO引脚、模数转换器、SPI、I2S、UART、PWM、I2C和SD卡接口等功能&#xff0c;可以满…

android 清除缓存方法

获得应用的存储信息 private void getAppStorageInfo(String packageName){StorageStatsManager storageStatsManager (StorageStatsManager) context.getSystemService(Context.STORAGE_STATS_SERVICE);StorageManager storageManager (StorageManager) context.getSystemS…

第二十一章 数据处理篇:imgaug

参考教程&#xff1a; https://imgaug.readthedocs.io/en/latest/source/jupyter_notebooks.html 文章目录 概述针对图片的增强基础使用样例base class: augment增强的组合sequentialsomeof和oneofsometimes 增强的种类 针对关键点的增强针对包围框的增强 概述 imgaug是一个使…

【深度学习】GPT-3

2020年5月&#xff0c;OpenAI在长达72页的论文《https://arxiv.org/pdf/2005.14165Language Models are Few-Shot Learners》中发布了GPT-3&#xff0c;共有1750亿参数量&#xff0c;需要700G的硬盘存储&#xff0c;(GPT-2有15亿个参数)&#xff0c;它比GPT-2有了极大的改进。根…