Spring Cloud 2.2.2 源碼之四十九nacos客戶端觸發服務刷新原理三

服務獲取和刷新的流程圖

在這裏插入圖片描述

NacosNamingService的selectInstances

前面說了,負載均衡器初始化的時候會最後調用NacosNamingServiceselectInstances方法,最終到這裏,因爲是訂閱標記是true,所以直接走hostReactor.getServiceInfo,內部如果發現服務有更新會進行監聽器的通知,所以叫做訂閱:
在這裏插入圖片描述

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事件:
在這裏插入圖片描述

PushReceiver接受推送

一旦註冊中心有服務改變了,就會進行推送,如果發現是dom類型的,表示有更新,所以就調用hostReactor.processServiceJSON,內部會進行更新,通知等操作,具體跟前面講過的updateServiceNow的結果處理一樣:
在這裏插入圖片描述

然後根據類型進行相應的應答UDP報文就好了:
在這裏插入圖片描述
因爲你請求刷新的時候會把UDP端口傳過去:
在這裏插入圖片描述

好了,服務刷新是如何做到的,是什麼時候刷新的現在基本已經瞭解了吧,除了自己去更新服務信息,服務端還會UDP推送過來。 流程圖也有了,可以自己debug一下加深理解,當然還有細節只能自己看啦,面面俱到我也做不到。

好了,今天就到這裏了,希望對學習理解有幫助,大神看見勿噴,僅爲自己的學習理解,能力有限,請多包涵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章