Nacos源码系列——第二章(Nacos核心源码主线剖析下)

上章节我这边带着大家看了下Nacos的源码,针对上节课做个总结:

  • Nacos服务注册过程深度剖析
  • Nacos注册表如何防止多节点读写并发冲突
  • Nacos高并发支撑异步队列与内存队列剖析
  • Nacos心跳机制(讲了一半)

那么本节课我们将继续带着大家往下看几个点

  • Nacos服务发现源码深度剖析
  • Nacos心跳机制与服务健康检查深度剖析
  • Nacos服务变动事件发布源码剖析

1、Nacos服务发现源码深度剖析

对于服务发现,Nacos在Server端提供了一个API,由官网可以看出:

https://nacos.io/zh-cn/docs/open-api.html

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第1张图片

 Nacos的客户端通过Server端暴露的API,进行拉取服务对应的ip等信息;

还是回到源码来看。

从NacosNamingService里的getAllInstances方法进行重载的执行。

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第2张图片

 边边角角的代码先不看,if判断像是订阅,getServiceInfo()见明知意,获取服务信息

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第3张图片

 再看getServiceInfo0();这里像是从一个缓存里去取出

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第4张图片

说明某个信息存在一个Map里,看看这个Map的结构

private final Map serviceInfoMap;

这个很明显,应该就是服务信息;

判断如果从缓存中取的为空,就去做这个操作

updateServiceNow(serviceName, clusters);

去更新缓存,实际上走的还是

/instance/list

看看代码

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第5张图片

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第6张图片

不管什么情况,最后会走到

scheduleUpdateIfAbsent(serviceName, clusters);

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第7张图片

里面是个定时任务UpdateTask,里面实际上是个run方法,定时获取服务端最新的数据更新到本地的任务。

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第8张图片

 所以到这,服务发现的主线源码,目前就比较清晰了。

2、Nacos心跳机制与服务健康检查深度剖析

        上节课讲心跳,讲到了一个类NamingService,核心的地方是添加一个BeatInfo

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第9张图片

         那BeanInfo是什么呢?构造组装一个心跳的实体,里面存放一些信息,比如当前服务名称+ip+端口+权重+当前属于什么cluster+心跳周期等等。

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第10张图片

         最终进入addBeanInfo,这里会new一个BeatTask任务,并且把5s作为一个周期去发送心跳。

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第11张图片

         会调用sendBeat方法去向Server端发送请求,instance/beat

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第12张图片

         来看server端的这个请求,其他的边线代码不看,看主线serviceManager.registerInstance()

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第13张图片

         里面是上节课说过的,注册一个instance实例,加入到本地缓存,加入到本地缓存作为服务实例,然后会立刻开启一个任务ClientBeatProcessor,更新客户端实例的最后心跳时间

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第14张图片

         最终调用instance.setLastBeat,上节说过,会比较当前实例的最后心跳时间和当前时间,如果超过15s无响应,健康状态置为false,超过30s,会下线此实例。

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第15张图片

        那么客户端是怎么感知服务端的服务是否存在,并及时更新状态或者下线的呢?

        当服务第一次注册上的时候,服务端会开启定时任务的检查

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第16张图片

         并且定时任务是5s执行一次

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第17张图片

         执行了之后就进入判断,这块不清楚的可以回顾上一章节Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第18张图片

         包括如何删除ip,也在这里面体现。

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第19张图片

         那么服务端的健康检查任务这里也讲了比较主要的过程。

3、Nacos服务变动事件发布源码剖析

        有没有考虑过一个问题,客户端会搞个定时任务定时拉取服务端的注册列表,那这么这个时间我假设是5s拉取一次,如果这个时候有服务下线或者替换,那么必须要等到下一个5s才知道这个服务不存在,这样的话实时性会跟不上,于是Nacos做了个主动推送的动作!

        先来回顾下服务发现的过程:

        在NacosNamingService.getAllInstance()中,获取客户端的服务实例缓存信息

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第20张图片

         如果获取的缓存为空,调用server获取最新的数据,updateServiceNow

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第21张图片

         然后延时执行定时任务,更新客户端的服务缓存scheduleUpdateIfAbsent(),最终进入到finally,定时执行这个任务,failCount默认值是0,Min计算当前延时的时间,和failCount最终的值进行左移运算,并和默认时间*60s做对比,这个过程中我们可以不详细解答,最坏的情况,Default_Delay*60=60s,也就是1min中会定时拉取最新数据缓存到客户端本地(这样的概率太低)。

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第22张图片

         这样显然可能会存在延时和数据不同步的问题,那么对于Nacos,做了个主动推送的机制。当服务端列表有变动的时候,服务端主动推送一个Udp请求,让客户端自己更新;

        在Service.onChange中,updateIPs里面会进行发布事件

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第23张图片

         serviceChanged方法里面进行事件的发布Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第24张图片

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第25张图片

         全文搜索下这个ServiceChangeEvent

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第26张图片

        里面有个UpdPush(),上面这么多逻辑代码都是在封装这个ackEntry,里面是一些服务端变化的信息,这个不是主线逻辑,我就不带大家看细节。Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第27张图片

         最终执行到updSocket.send()

Nacos源码系列——第二章(Nacos核心源码主线剖析下)_第28张图片

         udp相对会不稳定,和tcp不一样,所以网络丢包的时候会受到影响,当然丢了就丢了, 有变化再传一次就可以了,udp是不保证数据传输的稳定性的。那么这个策略,其实大大降低了ap架构中的数据不一致的风险。

        总结下:Zookeeper中在进行服务注册的时候,发起一个长连接,比如用Nio或者

Netty,会一直占用管道,而Nacos只是发起一个http请求,发起请求后就结束了,Nacos在

1.4.x版本中是典型的短链接(当然2.0后改用gRpc长连接),而Zk采用长连接方式建立通

道,如果在客户端服务器非常非常多,会比较耗性能的,Nacos相比会轻量不少哦,Zk为了

保证服务变动的一致性,监听回调机制就会立刻通知到客户端,响应是很及时的,所以Zk保

证了Cp,Nacos有两块保证了心跳,一块是客户端的定时拉取,一块是udp反向推送,即便

udp丢失了,也有定时任务兜底。

     

   本节就先讲述到这,下一章讲解Nacos集群架构下的同步源码!

你可能感兴趣的:(Dubbo微服务专题,java,Nacos)