Dubbo——註冊中心緩存機制、重試機制

緩存機制

緩存的存在就是用空間換取時間,如果每次遠程調用都要從註冊中心獲取一次可調用的服務列表,則會讓註冊中心承受巨大的流量壓力。另外,每次額外的網絡請求也會讓整個系統的性能下降。因此,Dubbo的註冊中心實現了通用的緩存機制,在抽象類AbstractRegistry中實現。

在這裏插入圖片描述

消費者或服務治理中心獲取註冊信息後會做本地緩存。內存中會有一份,保存在Properties對象裏,磁盤上也會持久化一份文件,通過file對象引用。

在AbstractRegistry抽象類中有如下定義:
在這裏插入圖片描述
內存中的緩存notified是ConcurrentHashMap裏面又嵌套了一個Map,外層Map的key是消費者的URL,內層Map的key是分類,包含providers、consumers、coutes、configurators四種。value則是對應的服務列表,對於沒有服務提供者提供服務的URL,它會以特殊的empty://前綴開頭。

緩存的加載

在服務初始化的時候,AbstractRegistry構造函數裏會從本地磁盤文件中把持久化的註冊數據讀到Properties對象裏,,並加載到內存緩存中:
在這裏插入圖片描述

Properties保存了所有服務提供者的URL,使用URL#serviceKey()作爲key,提供者列表、路由規則列表、配置規則列表等作爲value。由於value是列表,當存在多個的時候使用空格隔開。還有一個特殊的key.registies,保存所有的註冊中心的地址。如果應用在啓動過程中,註冊中心無法連接或宕機,則Dubbo框架會自動通過本地緩存加載Invokers。

緩存的保存與更新

緩存的保存有同步和異步兩種方式。異步會使用線程池異步保存,如果線程在執行過程中出現異常,則會再次調用線程池不斷重試:

在這裏插入圖片描述

AbstractRegistry#notify方法中封裝了更新內存緩存和更新文件緩存的邏輯。當客戶端第一次訂閱獲取全量數據,或者後續由於訂閱得到新數據時,都會調用該方法進行保存。
在這裏插入圖片描述

重試機制

com.alibaba.dubbo.registry.support.FailbackRegistry繼承了AbstractRegistry,並在此基礎上增加了失敗重試機制作爲抽象能力。ZookeeperRegistryRedisRegistry繼承該抽象方法之後,直接使用即可。

FailbackRegistry抽象類中定義了一個ScheduledExecutorService,每經過固定間隔(默認5秒)調用FailbackRegistry#retry()方法。另外,該抽象類中還有五個比較重要的集合:

結合名稱 集合介紹
Set failedRegistered 發起註冊失敗的URL集合
Set failedUnregistered 取消註冊失敗的URL集合
ConcurrentMap>failedSubscribed 發起訂閱失敗的監聽器集合
ConcurrentMap>failedUnsubscribed 取消訂閱失敗的監聽器集合
ConcurrentMap>>failedNotified 通知失敗的URL集合

在這裏插入圖片描述

在定時器中調用retyr方法的時候,會把這五個集合分別遍歷和重試,重試成功則從集合中移除。FailbackRegistry實現sbscribe、unsubscribe等通用方法,裏面調用額未實現的模板方法,會由子類實現。通用方法會調用這些模板方法,如果捕獲到異常,則會把URL添加到對應的重試結合中,以供定時器去重試。

註冊中心應用的設計模式

模板方法:

整個註冊中心的邏輯部分使用了模板模式:
在這裏插入圖片描述

AbstractRegistry實現了Registry接口中的註冊、訂閱、查詢、通知等方法,還實現了磁盤文件持久化註冊信息這一通用方法。但是註冊、訂閱、查詢、通知等方法只是簡單地把URL加入對應的集合,沒有具體的註冊或訂閱邏輯。

FailbackRegistry又繼承了AbstractRegistry,重寫了父類的註冊、訂閱、查詢和通知等方法,並且添加了重試機制。此外,還添加了四個未實現的抽象模板方法:

protected abstract void doRegister(URL url);
protected abstract void doUnregister(URL url);
protected abstract void doSubscribe(URL url, NtifyListener listener);
protected abstract void doUnsubscribe(URL url, NotifyListener listener);

工廠模式:

所有的註冊中心實現,都是通過對應的工廠創建的。

在這裏插入圖片描述
AbstractRegistryFactory實現了RegistryFactory接口的getRegistry(URL url)方法,是一個通用的實現,主要完成了加鎖,以及調用抽象模板方法,createRegistry(URL url)創建具體實現等操作,並緩存在內存中。抽象模板方法會由具體子類繼承並實現:

在這裏插入圖片描述

雖然每種註冊中心都有自己的具體工廠類,但是在什麼地方判斷,應該調用哪個工廠類實現呢?

答案就在RegistryFactory接口中,該接口裏有個Registry getRegistry(URL url)方法,該方法上有@Adaptive({"protocol"})註解:

在這裏插入圖片描述

這個註解會自動生成代碼實現一些邏輯,它的value參數會從URL中獲取protocol鍵的值,並根據獲取的值來調用不同的工廠類。

例如:當url.protocol=redis時,獲得RedisRegistryFactory實現類。

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