微服务学习-SpringCloud -Nacos (服务发现源码学习)

文章目录

  • 服务发现核心流程图
  • 微服务获取服务列表
  • 如果服务端列表发生了变化,本地缓存列表如何感知呢?
    • 第一种,本地缓存定时自动更新
    • 第二种,服务变动事件发布机制
    • 为何需要两种方式呢?
    • Nacos 和 Zookeeper 对比?

服务发现核心流程图

微服务学习-SpringCloud -Nacos (服务发现源码学习)_第1张图片

微服务获取服务列表

  • 总结来将,微服务获取服务列表主要就是:从本地缓存列表中获取,获取不到,发送请求到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方法:
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第2张图片
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第3张图片它里面又会去调用queryList方法查询最新的列表,然后更新到本地。

  • 总结
    nacos客户端会维护一个定时任务,定时去更新自己的本地缓存。
    默认时间是多久呢? 5秒。

第二种,服务变动事件发布机制

我们在服务注册时,会调用一个方法,查看我之前画的服务注册的流程图,会调用updateIPs方法:
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第4张图片
我们看一下具体源码:
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第5张图片
监听数据变化。
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第6张图片
然后调用updateIPs方法,

微服务学习-SpringCloud -Nacos (服务发现源码学习)_第7张图片
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第8张图片
Spring的事件发布,发布了这样一个数据变化的事件。
然后我们看一下事件接收后的处理,找到对应的接收类:
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第9张图片
然后进入udpPush(ackEntry);方法:
微服务学习-SpringCloud -Nacos (服务发现源码学习)_第10张图片
通过UPD的方式发送给客户端完成更新。

为何需要两种方式呢?

第二种主动推送的方式是使用了UPD的方式,是不可靠的,有可能发生丢包。所以通过第一种定时拉取方式来进行兜底,即使主动推送失败了,也可以通过定时拉取的方式完成更新。

Nacos 和 Zookeeper 对比?

  • Zookeeper客户端和服务端主要是通过TCP长连接,建立连接之后会通过这个管道发起心跳,让管道一直存活,保持一个长链接。
  • Nacos注册时会向服务端发起一个Http请求,注册完成后就结束了,是一个短连接。
  • 当服务器特别多的时候,如果都建立长连接,是比较费性能的。
  • 当服务有变动时,Zookeeper通过回调技术,响应是非常及时的。而nacos也算比较及时的,主要是通过UDP将变动通知给客户端,即使UPD方式失败了,也可以通过定时任务进行更新,就是感知会稍慢几秒钟,相比于Zookeeper有一点延迟。

你可能感兴趣的:(微服务,微服务,学习,spring,cloud)