1.处理客户端请求
找到 InstanceController
@RequestMapping(UtilsAndCommons.NACOS_NAMING_CONTEXT + "/instance")
这个地址就是我们客服端注册服务的地址 客服端服务的注册流程可以去看这篇博文【Spring Cloud 】 Nacos 服务注册过程 源码_秋日的晚霞的博客-CSDN博客
看controller方法
上来先拿到 namespaceId 和 serviceName
默认命名空间 : public
分组 : DEFAULT_GROUP@@ + 客户端注册的服务名
解析 instance 对象 封装了服务提供者的参数
接下来注册服务 调用 registerInstance 方法
serviceManager.registerInstance(namespaceId, serviceName, instance);
跟进去 来到
com.alibaba.nacos.naming.core.ServiceManager. registerInstance
2.注册实例
com.alibaba.nacos.naming.core.ServiceManager. registerInstance
首先调用 createEmptyService 在注册表里面创建一个空的service结构
跟进去 来到 createServiceIfAbsent 方法
第一次进来 Service service = getService(namespaceId, serviceName) 肯定是null
进入if逻辑
创建了一个新的 service 对象 设置 服务名,命名空间,分组名 记录修改时间
来到 putServiceAndInit(service)
跟进去
`serviceMap 双层map
看下执行完putService后serviceMap 的数据
外层map的key为 namespace value也为一个map,内层map的key为 groupName 分组名 value为 service对象
3.服务实例心跳检查
回到 putServiceAndInit 方法
接着执行 service.init() 方法
来到 com.alibaba.nacos.naming.core.Service.init 方法
执行一个定时任务 第一次5秒后执行,然后每隔5秒执行一次 看下线程任务时什么 跟进task
线程任务
com.alibaba.nacos.naming.healthcheck.ClientBeatCheckTask.run()
`instance.getInstanceHeartBeatTimeOut() 值是15秒
如果当前时间 减去 实例最后一次心跳时间 大于 15秒 进 if判断 将健康状态设置为false
也就是说 HealthCheckReactor.scheduleCheck(clientBeatCheckTask) 开启了一个心跳检测所有的实例健康状态,一旦距离上一次心跳检测时间超过15 s 将健康状态设置为false
4.发送消息给队列
回到 registerInstance 方法
继续看 addInstance(namespaceId, serviceName, instance.isEphemeral(), instance)
跟进去来到 com.alibaba.nacos.naming.core.ServiceManager.addInstance
首先生成一个实例key 值 com.alibaba.nacos.naming.iplist.ephemeral.public##DEFAULT_GROUP@@nacos-test
String key = KeyBuilder.buildInstanceListKey(namespaceId, serviceName, ephemeral);
生成实例集合
List<Instance> instanceList = addIpAddresses(service, ephemeral, ips)
new Instances 封装集合数据
Instances instances = new Instances();
instances.setInstanceList(instanceList);
来到consistencyService.put(key, instances) 方法
来到 com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl.put
`Record value 就是封装Instance 的 Instances instances Instances 继承 Record 多态的体现
跟进 onPut 方法
来到 com.alibaba.nacos.naming.consistency.ephemeral.distro.DistroConsistencyServiceImpl.onPut 方法
又new 了一个 Datum 对象 Datum value为 Instances key为前面生成的实例key
然后又把Datum 丢到 DataStore的map 中
最后调用 notifier.addTask方法 跟进addTask方法
往services中put key为 datumKey value为空字符串
private ConcurrentHashMap<String, String> services = new ConcurrentHashMap<>(10 * 1024)
最后调用task.offer
将这个key和执行的动作扔到内存队列中 然后返回null了 方法结束了
难度到这就结束了吗?
5.监听队列,取出新服务实例
我们看下这个tasks所属的类
`Notifier 也是一个线程任务类 ,那么我们看下它的线程任务
从队列中拿到datumKey 调用handle 方法
打个断点,看下执行流程,重新注册服务
来到 listener.onChange
onChange方法的两个参数 一个为 datumKey 一个为 Instances
可以看到 又把服务实例集合通过datumKey 从dataStore中拿出来了
跟进去 来到com.alibaba.nacos.naming.core.Service.onChange方法
遍历所有的instance实例 设置合理的权重
然后调用 updateIPs 方法 跟进去
上来又new了一个 ipMap 好多map
遍历所有的instance
添加到 clusterIPs 中
再到下面一个for遍历
调用 clusterMap.get(entry.getKey()).updateIps(entryIPs, ephemeral) 拿到cluster调用updateIps 方法
来到 com.alibaba.nacos.naming.core.Cluster.updateIps
6.写时复制,注册新服务实例到注册表中
ephemeral 上个方法传进来的参数,为true,则将 ephemeralInstances 的赋值给 Set toUpdateInstances
Set<Instance> toUpdateInstances = ephemeral ? ephemeralInstances : persistentInstances;
那这个 ephemeralInstances 是什么呢
它就是 Cluster存放服务实例的set旧集合
private Set<Instance> ephemeralInstances = new HashSet<>();
将旧的实例集合赋值给了 toUpdateInstances 接下来就是操作新注册的服务实例,最后再将所有的最新的实例赋值给toUpdateInstances,
然后再将 toUpdateInstances 的值赋值给 ephemeralInstances 至此一个新的服务实例注册完毕
这就是一种写时复制的思想,将注册好的服务实例,复制一份,操作这份复制的数据,操作完毕后,再将复制的数据替换原来的旧数据
目的是为了解决并发冲突,在写的过程中,其他线程读到的还是旧数据,等真正写完之后再将数据更新回去。不会读到脏数据.保证读到的服务实例都是可用的