Dubbo——Directory的實現原理

Directory的實現

整個容錯過程中首先會使用Directory#list來獲取所有的Invoker列表。Directory也有多種實現子類,既可以提供靜態的Invoker列表,也可以提供動態的Invoker列表。靜態的列表是用戶自己設置的Invoker列表;動態列表根據註冊中心的數據動態變化,動態更新Invoker列表的數據,整個過程對上層透明。

總體實現

在這裏插入圖片描述

Directory是頂層接口。AbstractDirectory封裝了通用的實現邏輯。抽象類包含RegistryDirectory和StaticDirectory兩個子類。

AbstractDirectory:
封裝了通用邏輯,主要實現了四個方法:檢測Invoker是否可用,銷燬所有Invoker,list方法,還留了一個抽象的doList方法給子類自行實現。list方法是最主要的方法,用於放回所有可用的list,邏輯分爲兩步:

  1. 調用抽象方法doList獲取所有Invoker列表,不同子類有不同的實現;
  2. 遍歷所有的router,進行Invoker過濾,最後返回過濾好的Invoker列表。

doList抽象方法則是返回所有的Invoker列表,由於是抽象方法,子類繼承後必須要有自己的實現。

RegistryDirectory:
屬於Directory的動態列表實現,會自動從註冊中心更新Invoker列表、配置信息、路由列表。

StaticDirectory:
Directory的靜態列表實現,即將出阿奴的Invoker列表封裝成靜態的Directory對象,裏面的列表不會改變。因爲Cluster#join(Directory<T> directory)方法需要傳入Directory對象,因此該實現主要使用一些上層已經知道自己要調用哪些Invoker,只需要包裝一個Direcotry對象返回即可的場景。在ReferenceConfig#createProxyRegistryDirectory#toMergeMethodInvokerMap中使用了Cluster#join方法。StaticDirectory的邏輯非常簡單,在構造方法中需要傳入Invoker列表,doList方法則直接返回初始化傳入的列表。

RegistryDirectory的實現

RegistryDirectory中有兩條比較重要的邏輯線,第一條:框架與註冊中心的訂閱,並動態更新本地Invoker列表、路由列表、配置信息的邏輯;第二條:子類實現父類的doList方法。

1. 訂閱與動態更新:
這個邏輯主要涉及subscribe、notify、refreshInvoker三個方法,其餘是一些數據轉換的輔助類方法,如toConfigurators、toRouters。

subscribe是訂閱某個URL的更新信息。Dubbo在引用每個需要RPC調用的Bean的時候,會調用directory.subscribe來訂閱這個Bean的各種URL的變化(Bean的 配置在配置中心都是以URL的形式存放的)。這個方法比較簡單,只有兩行代碼,僅僅使用registry.suscribe訂閱。
在這裏插入圖片描述

notify就是監聽到配置中心對應的URL的變化,然後更新本地的配置參數。監聽的URL分爲三類:配置configurators、路由規則router、Invoker列表。工作流程如下:

  • 新建三個List,分別用於保存更新三類變化。遍歷監聽返回的所有URL,分類後放入三個List中
  • 解析並更新配置參數:
    1. 對於router類型的參數,首先遍歷所有router類型的URL,然後通過Router工廠把每個URL包裝成路由規則,最後更新本地的路由信息。這個過程會忽略以empty開始的URL。
    2. 對於Configurator類的參數,管理員可以在dubbo-admin動態配置功能上修改生產者的參數,這些參數會保存在配置中心的configurators類目下。notify監聽到URL配置參數的變化,會解析並更新本地的Configurator配置。
    3. 對於Invoker類型的參數,如果是empty協議的URL,則會禁用該服務,並銷燬本地緩存的Invoker;如果監聽到的Invoker類型URL都是空的,則說明沒有更新,直接使用本地緩存;如果監聽到的Invoker類型URL不爲空,則把新的URL和本地老的URL合併,創建新的Invoker,找出差異的老Invoker並銷燬。

dubbo-admin上更新路由規則或參數是通過"override://"協議實現的,dubbo-admin的使用方法可以查看官方文檔。override協議的URL會覆蓋更新本地URL中對應的參數。如果是"empty://"協議的URL,則會情況本地的配置,這裏會調用Configurator接口來實現該功能。

override參數示例:

overrie://10.20.155.1/com.test.DemoServer?category=configurators&dynamic=false&enabled=true&application=test&timeout=1000


overrie://  override協議
10.20.155.1 如果是0.0.0.0,則表示對所有服務生效。具體IP則表示只覆蓋具體IP的。必填
com.test.DemoServer 表示只對指定的服務生效,必填
category=configurators 表示這個參數是動態配置的,必填
dynamic=false  是否持久化,false爲持久化數據。註冊方退出,數據依然會保留在註冊中心,必填
enabled=true 覆蓋規則是否生效,默認生效,可以不填
application=test  針對某個應用生效,不填則對所有應用生效,可以不填
timeout=1000   表示將滿足前面的條件的timeout參數覆蓋爲1000

2. doList的實現:

notify中更新的Invoker列表最終會轉化爲一個字典Map<String, List<Invoker<T>>> mthodInvokerMap。key是對應的方法名稱,value是整個Invoker列表。doList的最終目的就是在字典裏匹配出可以調用的Invoekr列表,並返回給上層。其主要步驟如下:

  1. 檢查服務是否被禁用。如果配置中心禁用了某個服務,則該服務無法被調用。如果服務被禁用則會拋出異常。
  2. 根據方法名和首參數匹配Invoekr。這是一個比較奇怪的特性。根據方法名和首參數查找對應的Invoker列表,暫時沒看到相關的應用場景。
//首參數匹配Invoker使用示例
void test(String arg); //假設有test方法
test("123); //調用
test.123  //用test.123在methodInvokerMap中匹配對應的Invoker列表

如果在這一步沒有匹配到Invoker列表,則進入第三步。

  1. 根據方法名匹配Invoker。以方法名爲key去methodInvokerMap中匹配Invoker列表,如果還是沒有匹配到,則進入第四步。
  2. 根據"*"匹配Invoker。用星號去匹配Invoker列表,如果還沒有匹配到,則進入最後一步兜底操作。
  3. 遍歷methodInvokerMap,找到第一個Invoker列表返回。如果還沒有,則返回一個空列表。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章