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

Posted 风清扬逍遥子

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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的客户端通过Server端暴露的API,进行拉取服务对应的ip等信息;

还是回到源码来看。

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

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

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

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

private final Map<String, ServiceInfo> serviceInfoMap;

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

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

updateServiceNow(serviceName, clusters);

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

/instance/list

看看代码

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

scheduleUpdateIfAbsent(serviceName, clusters);

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

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

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

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

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

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

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

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

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

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

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

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

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

         执行了之后就进入判断,这块不清楚的可以回顾上一章节

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

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

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

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

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

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

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

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

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

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

         serviceChanged方法里面进行事件的发布

         全文搜索下这个ServiceChangeEvent

        里面有个UpdPush(),上面这么多逻辑代码都是在封装这个ackEntry,里面是一些服务端变化的信息,这个不是主线逻辑,我就不带大家看细节。

         最终执行到updSocket.send()

         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集群架构下的同步源码!

以上是关于Nacos源码系列——第二章(Nacos核心源码主线剖析下)的主要内容,如果未能解决你的问题,请参考以下文章

Nacos源码系列 源码编译

Nacos源码系列——第三章(全网最经典的Nacos集群源码主线剖析)

九:Alibaba Nacos注册中心源码剖析

《跟二师兄学Nacos吧》第1篇 Nacos客户端服务注册源码分析

《跟二师兄学Nacos吧》第1篇 Nacos客户端服务注册源码分析

Nacos源码系列—订阅机制的前因后果(上)