深度解析nacos源码之注册中心(服务主动下线)

原创不易,转载请注明出处
本文基于nacos1.4.0


前言

nacos作为注册中心,支持两种服务下线,一种是客户端主动调用api向服务端发送服务下线,然后实现服务下线,第二种就是服务故障,然后服务端很长时间没有收到某个实例的心跳信息,服务端就会将这个服务健康状态设置成false,也就是标志不健康状态(这个时间默认是15s,也就是15s服务端没有收到某个服务的心跳信息),如果更长时间没有收到心跳信息,直接就会将这个服务摘除(默认是30s)。关于故障下线的源码实现我们别的篇章会介绍,本文主要是分析下这个服务主动下线部分的源码。

1.客户端请求服务下线

Properties properties = new Properties();
properties.setProperty("serverAddr", "127.0.0.1:8845");
properties.setProperty("namespace","public");

NamingService naming = NamingFactory.createNamingService(properties);
// 先注册
naming.registerInstance("userService", "11.11.11.11", 8888, "DEFAULT");
// 后下线
naming.deregisterInstance("userService", "11.11.11.11", 8888, "DEFAULT");

还是使用example这个子项目中的NamingExample 类为例子。我们可以看到,是先注册,然后调用deregisterInstance 方法进行服务主动下线。这个NameService中服务下线的api 重载也是非常的多
在这里插入图片描述
在这里插入图片描述
可以使用serviceName, group,cluster不同条件来进行服务下线。如果你group没有设置就是使用默认的DEFAULT_GROUP,如果你集群没有设置的话,也是使用默认的DEFAULT, serviceName , ip,port这三个条件必须得有。
在这里插入图片描述
会封装成一个instance,把serviceName,ip,port,集群都塞进去
在这里插入图片描述
如果是临时节点的话,就会调用beatReactor这个组件移除beatInfo这个任务,就是不用再发送心跳续约了。接着就是调用serverProxy这个组件的deregisterService 方法进行服务下线,这里需要注意的是NamingUtils.getGroupedName(serviceName, groupName)这行代码,它是将group与serviceName 使用@@ 拼到了一起,然后作为这个服务serviceName, 我们在服务注册的时候也是这样拼装过,所以服务下线的时候也需要拼装下。
在这里插入图片描述
组装请求参数,然后是调用reqApi 发送请求,请求的uri是/nacos/v1/ns/instance, 请求方式是delete ,也就是使用restful风格。
在这里插入图片描述
其实再往下就与服务注册客户端请求的代码一样了,这里就是先随机选择一个server,然后调用callServer方法进行发送,如果异常的话,就往下轮询其他server进行发送请求,你有多少个server 就重试多少次。往下的代码与服务注册请求都一样,其实就是拼装url,发送请求,好了, 客户端的主动下线部分我们就解析完成了。

2.服务端处理服务主动下线

客户端请求会被InstanceController 这个controller处理,其实与instance有关的请求都是这个controller 来处理。InstanceController的deregister这个方法就是服务下线。
在这里插入图片描述
前面代码都是解析请求参数的,我们需要关注serviceManager.getService 与serviceManager.removeInstance 这两个行代码的调用,serviceManager.getService 其实就是根据namespace与serviceName 从serviceMap 这个map中获取对应的service 实例,如果没有的话,就说明没有之前没有注册过,也就直接返回ok了,如果存在的话,就会调用serviceManager.removeInstance 移除这个instance。
在这里插入图片描述
这个方法没啥好看的,先获取一下这个namespace与serviceName对应的service实例,然后加锁,调用removeInstance 方法进行移除。
在这里插入图片描述
先生成一个服务列表的key这个key与你instance是否是临时节点有关系,如果是临时节点,生成的key是这个样子的com.alibaba.nacos.naming.iplist.ephemeral.{namespace}##{serviceName} 永久节点就是com.alibaba.nacos.naming.iplist.{namespace}##{serviceName} 这个样子。
接着就是调用substractIpAddresses 方法用之前的instance列表减去 这次要下线的实例列表,然后生成一份新的剖去下线的实例列表。
在这里插入图片描述
UPDATE_INSTANCE_ACTION_REMOVE这个action是remove。接着调用updateIpAddresses 方法。
在这里插入图片描述
其实就是将之前的instance弄出来,然后放到这个instanceMap中,然后遍历这个要删除的instance集合,如果是删除action的话,就从instanceMap中移除这个DatumKey,这个key就是这个样子 ip:port:unknown:{cluster}。到最后这个instanceMap就剩下抛去我们要下线的instance了。
接着removeInstance 这个方法往下看,就是创建一个instances对象,然后将instance集合塞到这里面。接着就是交给consistencyService组件来进行put操作。这里其实就是调用了EphemeralConsistencyService的实现类DistroConsistencyServiceImpl 的put方法。往下的步骤我们就不赘述了,再往下就与服务注册后续的逻辑一摸一样的,就是封装instance集合与key ,封装成一个Datum,然后将这个Datum 塞到dataStore 这个存储组件中,这个组件实际就是个map。
接着就是往Notifier 这个组件里面的一个task队列添加一个事件通知任务,然后就完事了(其实这里还有向其他server 同步的步骤,我们这里暂时先不研究),就可以将响应返回给客户端了。这个时候,其实service 对象里面的instance列表并没有更新,这就是所谓nacos的异步注册异步下线,会有一个后台线程,不停的从Notifier组件中的task 队列中取出task,然后调用handle方法进行事件通知,其实就通知到service 对象的onChange 方法里面了,其实更新操作都是这个方法做的。具体的源码分析可以看下《深度解析nacos源码之注册中心(服务注册)》这篇文章,因为后面都是重复的内容,我们这里也就不再赘述了。也可以看下《深度解析nacos源码之注册中心(服务注册流程图补充)》这篇文章,然后好好理解下这个nacos所谓的异步注册是怎样实现的。

  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

$码出未来

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值