2023-09-15  阅读(2)
原文作者:王伟王胖胖 原文地址: https://blog.csdn.net/wangwei19871103/article/details/105798803

服务获取和刷新的流程图

202309152317478341.png

NacosNamingService的selectInstances

前面说了,负载均衡器初始化的时候会最后调用NacosNamingServiceselectInstances方法,最终到这里,因为是订阅标记是true,所以直接走hostReactor.getServiceInfo,内部如果发现服务有更新会进行监听器的通知,所以叫做订阅:

202309152317494742.png

HostReactor的getServiceInfo

先判断容灾模式,如果已经出故障了,直接从本地缓存读取。否则就尝试获取服务信息,如果没有就创建一个,然后立即去注册中心获取服务,这里用了一个updatingMap来表示再更新的服务,然后进行更新,里面涉及更新后的结果和老的做比对,如果有改变,会对Notifier任务进行改变通知,其实就是改变了阻塞队列changedServicesNotifier检查到他有改变,就会进行处理,去通知监听器有NamingEvent事件,不过貌似目前还没有监听这个事件的监听器。完了最后再判断是否这个服务已开启UpdateTask任务更新,没有的话就开启一个UpdateTask任务进行更新,这里才是真正更新服务,对已有的服务进行更新,而负载均衡的PollingServerListUpdater任务,更多的是获取服务,真正的服务更新还是UpdateTask任务做的。

        public ServiceInfo getServiceInfo(final String serviceName, final String clusters) {
    
            NAMING_LOGGER.debug("failover-mode: " + failoverReactor.isFailoverSwitch());
            String key = ServiceInfo.getKey(serviceName, clusters);
            if (failoverReactor.isFailoverSwitch()) {//已经到容灾模式
                return failoverReactor.getService(key);
            }
    
            ServiceInfo serviceObj = getServiceInfo0(serviceName, clusters);
    
            if (null == serviceObj) {//不存在就创建
                serviceObj = new ServiceInfo(serviceName, clusters);
    
                serviceInfoMap.put(serviceObj.getKey(), serviceObj);
                //updatingMap表示在更新了
                updatingMap.put(serviceName, new Object());
                updateServiceNow(serviceName, clusters);
                updatingMap.remove(serviceName);
    
            } else if (updatingMap.containsKey(serviceName)) {
                //正在更新实例
                if (UPDATE_HOLD_INTERVAL > 0) {
                    // hold a moment waiting for update finish
                    synchronized (serviceObj) {
                        try {
                            serviceObj.wait(UPDATE_HOLD_INTERVAL);
                        } catch (InterruptedException e) {
                            NAMING_LOGGER.error("[getServiceInfo] serviceName:" + serviceName + ", clusters:" + clusters, e);
                        }
                    }
                }
            }
    
            scheduleUpdateIfAbsent(serviceName, clusters);
    
            return serviceInfoMap.get(serviceObj.getKey());
        }

HostReactor的scheduleUpdateIfAbsent

双重检测,添加一个UpdateTask任务。这个任务具体干什么,我在前面的文章
里有,就不多说了。

     public void scheduleUpdateIfAbsent(String serviceName, String clusters) {
            if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
                return;
            }
    
            synchronized (futureMap) {
                if (futureMap.get(ServiceInfo.getKey(serviceName, clusters)) != null) {
                    return;
                }
    
                ScheduledFuture<?> future = addTask(new UpdateTask(serviceName, clusters));
                futureMap.put(ServiceInfo.getKey(serviceName, clusters), future);
            }
        }

如果有新的服务获取到,或者有服务改变了,Notifier任务会感知到,然后去通知监听器,不过没监听器监听NamingEvent事件:

202309152317500753.png

PushReceiver接受推送

一旦注册中心有服务改变了,就会进行推送,如果发现是dom类型的,表示有更新,所以就调用hostReactor.processServiceJSON,内部会进行更新,通知等操作,具体跟前面讲过的updateServiceNow的结果处理一样:

202309152317508004.png

然后根据类型进行相应的应答UDP报文就好了:

202309152317516405.png
因为你请求刷新的时候会把UDP端口传过去:

202309152317533646.png

好了,服务刷新是如何做到的,是什么时候刷新的现在基本已经了解了吧,除了自己去更新服务信息,服务端还会UDP推送过来。 流程图也有了,可以自己debug一下加深理解,当然还有细节只能自己看啦,面面俱到我也做不到。

好了,今天就到这里了,希望对学习理解有帮助,大神看见勿喷,仅为自己的学习理解,能力有限,请多包涵。


Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。

它的内容包括:

  • 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
  • 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
  • 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
  • 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
  • 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
  • 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
  • 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
  • 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw

目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:

想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询

同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。

阅读全文