【源码系列】Nacos客户端服务发现原理源码


客户端服务发现原理源码

客户端服务发现

上一篇Nacos服务注册原理源码文章中,在Nacos提供的注册中心测试单元中代码,我们只讲到了服务的注册,注册完后,服务获取方法没有往下展开分析,今天我们主要就是讲解这个方法。
请添加图片描述

这个方法有很多重载方法,调用时加上一些默认请求参数比如:集群列表、是否订阅、分组 最终会调到下面这个方法中,通过代码能看到如果是订阅模式,会先从本地获取,如果本地不存在,会进行服务订阅,订阅时会返回对应的服务数据,如果是非订阅模式的话,调用服务端的查询接口进行查询。请添加图片描述

服务订阅并获取

根据常识也能知道如果不从Nacos服务端获取服务信息,第一次本地缓存肯定不存在对应的服务信息,所以先分析订阅并获取,通过NacosNamingService#init可以知道会走到NamingClientProxyDelegate#subscribe该方法代码如下
请添加图片描述
通过group@@serviceName先从ServiceInfoHolder对象中服获取对应的服务信息,不存在的话就通过grpc向服务端发送请求,返回结果后,如果是订阅模式,会开启定时任务更新本地缓存,定时执行的逻辑如下:
请添加图片描述
其实订阅的每个服务都为他们开了个定时任务来同步注册中心的服务实例信息,具体逻辑为每隔一段时间(默认6s)从本地缓存中获取服务的信息,判断是否过期,过期重新请求服务端,进行缓存处理,修改最新的服务获取时间。操作缓存方法processServiceInfo,这个方法比较重要,我们来看下它具体的代码请添加图片描述
可以看到它将获取到的ServiceInfo存到了一个名为serviceInfoMap的集合中,然后判断服务的是否发生变更,如果变更过发现服务变更的事件,并将新的ServiceInfo存到本地文件中。请添加图片描述

服务端收到订阅服务请求后面会分析。

服务本地内存获取

其实理解了上面讲的订阅,其实这个就很简单了,定时任务将注册中心同步过来的服务存放到ServiceInfoHolder下面这个属性中

private final ConcurrentMap<String, ServiceInfo> serviceInfoMap;

我们看下获取服务的方法
请添加图片描述

通过代码发现,如果没有开启故障转移开关,就会从集合汇总拿,故障转移后面会讲到,到这里客户端的服务发现原理基本讲完了。

服务端服务订阅处理

服务订阅的处理方法是SubscribeServiceRequestHandler#handle,先获取服务的信息,如果是订阅模式获取,会发布一个服务订阅的事件,事件处理核心就是将该客户端添加到ClientServiceIndexesManager#subscriberIndexes缓存中(后期如果订阅的服务发生变更,会通知到客户端)再通过传递的serviceName拿到服务实例,拿着Service对象去serviceStorage中取数据
请添加图片描述
看过上一篇务 注册原理源码的应该知道,我们在注册的时候先构建了单例的Service,服务注册到了ClientServiceIndexesManager#publisherIndexesmap集合中,存储结构如下图,之前不是说map集合才是注册表嘛,但是这里怎么去serviceStorage中获取啦,其实该对象最终还是去注册表中取的我们接着往下看。
请添加图片描述

下面代码就是获取服务信息的方法,为了方便看我把这些方法都放在一张图中,如果ServiceStorage#serviceDataIndexes缓存中存在该服务实例,则直接从缓存中取,不存在就从serviceIndexesManager(注册表)中取,取出后设置到ServiceStorage#serviceDataIndexes中,并返回
请添加图片描述
补一个服务端简单服务获取的流程图:
请添加图片描述

客户端故障转移

如果Nacos服务端宕机了,为了保证服务的正常调用,Nacos提供了故障转移机制, ServiceInfoHolder对象在实例化的时候,初始化了缓存目录同时也创建了故障转移的对象FailoverReactor
请添加图片描述

我们看下故障转移对象初始化做了些啥
请添加图片描述

通过代码,发现故障转移对象还持有了本地缓存ServiceInfoHolder对象,创建了一个线程池、还进行了对应的初始化操作。我们看下初始化方法的代码,初始化方法中就是创建了三个定时任务,第一个通过名称我们也能才到,该定时任务用来判断是否需要开启故障转移的,至于第二个、第三个

细心的同学会发现,第二个任务和第三个任务实际上是一个,只是触发的时机不同而已,一个30分钟执行一次,时间间隔为24小时,另一个是10s后执行一次,只会执行一次。
请添加图片描述

我们先看第二、三个定时任务,这两个任务执行的都是同一段代码,第一个定时任务读取的内容其实是第二三个任务写到故障文件中的。故障转移对象先从本地缓存中拿出服务的实例信息,然后写到了磁盘中。
请添加图片描述
再来看第一个定时任务,发现它5s中会去读取故障转移开关文件,1表示开启故障转移,0代表关闭故障转移。实际上他们都是往FailoverReactor#switchParams该集合中添加了一个属性值failover-mode,该属性就是之前在本地获取服务实例信息时用来判断是否开启了故障转移功能。
请添加图片描述请添加图片描述
如果开启了故障转移,会去读取故障转移文件,中间读取的代码忽略,我们只需要关注读取到的实例信息放的位置,它会将实例信息放到FailoverReactor#serviceMap中,当获取服务发现开启了故障转移时,就会从该集合中来读取服务信息。
请添加图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值