微服务学习-SpringCloud -Nacos (服务发现源码学习)
文章目录
- 服务发现核心流程图
- 微服务获取服务列表
- 如果服务端列表发生了变化,本地缓存列表如何感知呢?
-
- 第一种,本地缓存定时自动更新
- 第二种,服务变动事件发布机制
- 为何需要两种方式呢?
- Nacos 和 Zookeeper 对比?
服务发现核心流程图
微服务获取服务列表
- 总结来将,微服务获取服务列表主要就是:从本地缓存列表中获取,获取不到,发送请求到nacos服务端获取。
如果服务端列表发生了变化,本地缓存列表如何感知呢?
第一种,本地缓存定时自动更新
我们之前在服务注册看到过这段代码:
public ServiceInfo getServiceInfo(String serviceName, String clusters) {LogUtils.NAMING_LOGGER.debug("failover-mode: " + this.failoverReactor.isFailoverSwitch());String key = ServiceInfo.getKey(serviceName, clusters);if (this.failoverReactor.isFailoverSwitch()) {return this.failoverReactor.getService(key);} else {// 服务发现核心方法ServiceInfo serviceObj = this.getServiceInfo0(serviceName, clusters);if (null == serviceObj) {serviceObj = new ServiceInfo(serviceName, clusters);this.serviceInfoMap.put(serviceObj.getKey(), serviceObj);this.updatingMap.put(serviceName, new Object());// 查询最新的服务列表this.updateServiceNow(serviceName, clusters);this.updatingMap.remove(serviceName);} else if (this.updatingMap.containsKey(serviceName)) {synchronized(serviceObj) {try {serviceObj.wait(5000L);} catch (InterruptedException var8) {LogUtils.NAMING_LOGGER.error("[getServiceInfo] serviceName:" + serviceName + ", clusters:" + clusters, var8);}}}// 本地列表更新核心方法this.scheduleUpdateIfAbsent(serviceName, clusters);return (ServiceInfo)this.serviceInfoMap.get(serviceObj.getKey());}}
我们进入 this.scheduleUpdateIfAbsent(serviceName, clusters)方法
public void scheduleUpdateIfAbsent(String serviceName, String clusters) {if (this.futureMap.get(ServiceInfo.getKey(serviceName, clusters)) == null) {synchronized(this.futureMap) {if (this.futureMap.get(ServiceInfo.getKey(serviceName, clusters)) == null) {// 核心代码,添加一个线程任务ScheduledFuture<?> future = this.addTask(new HostReactor.UpdateTask(serviceName, clusters));this.futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);}}}}
主要看下UpdateTask方法:
它里面又会去调用queryList方法查询最新的列表,然后更新到本地。
- 总结
nacos客户端会维护一个定时任务,定时去更新自己的本地缓存。
默认时间是多久呢? 5秒。
第二种,服务变动事件发布机制
我们在服务注册时,会调用一个方法,查看我之前画的服务注册的流程图,会调用updateIPs方法:
我们看一下具体源码:
监听数据变化。
然后调用updateIPs方法,
Spring的事件发布,发布了这样一个数据变化的事件。
然后我们看一下事件接收后的处理,找到对应的接收类:
然后进入udpPush(ackEntry);方法:
通过UPD的方式发送给客户端完成更新。
为何需要两种方式呢?
第二种主动推送的方式是使用了UPD的方式,是不可靠的,有可能发生丢包。所以通过第一种定时拉取方式来进行兜底,即使主动推送失败了,也可以通过定时拉取的方式完成更新。
Nacos 和 Zookeeper 对比?
- Zookeeper客户端和服务端主要是通过TCP长连接,建立连接之后会通过这个管道发起心跳,让管道一直存活,保持一个长链接。
- Nacos注册时会向服务端发起一个Http请求,注册完成后就结束了,是一个短连接。
- 当服务器特别多的时候,如果都建立长连接,是比较费性能的。
- 当服务有变动时,Zookeeper通过回调技术,响应是非常及时的。而nacos也算比较及时的,主要是通过UDP将变动通知给客户端,即使UPD方式失败了,也可以通过定时任务进行更新,就是感知会稍慢几秒钟,相比于Zookeeper有一点延迟。