Dubbo註冊中心 Zookeeper原理與實現
點關注不迷路,歡迎再訪!
精簡博客內容,儘量已行業術語來分享。
努力做到對每一位認可自己的讀者負責。
幫助別人的同時更是豐富自己的良機。
一.Zookeeper原理介紹
Zookeeper 是樹形結構的註冊中心,Dubbo使用zookeeper作爲註冊中心時,只會創建持久節點和臨時節點兩種,對創建的順序並沒有要求。結構如下:
+/dubbo
±- service
±- providers
± - consumers
± - routers
± - configurators
二.Zookeeper 的實現
2.1 發佈的實現
服務提供者:註冊是爲了讓消費者感知服務的存在,從而發起遠程調用;也讓服務治理中心感知有新的服務提供者上線;
消費者 :發佈是爲了讓服務治理中心可以發現自己。
zkClient創建目錄源碼
zkClient.create(toUrlPath(url),url.getParameter(Constants.DYNAMIC_KEY,true));
2.2 訂閱的實現
訂閱常用方式:
pull : 客戶端定時輪詢註冊中心拉取配置;
push : 註冊中心主動推送數據給客戶端。
目前dubbo採用pull方式,後續接收事件重新拉取數據。採用“事件通知” + “客戶端拉取”的方式,客戶端第一次連接上註冊中心時,會獲取對應目錄下全量的數據。並再訂閱的節點上註冊一個watcher,客戶端與註冊中心之間保持TCP長連接,後續每個節點有任何數據變化,註冊中心會根據watcher的回調主動通知客戶端,客戶端接到通知後會把對應節點下的權力數據都拉取過來。
消費者的訂閱邏輯:
根據URL的類別得到一組需要訂閱的路徑。如果類別是*,則會訂閱所有類型路徑,否則只訂閱providers路徑,源碼:
List<URL> urls = new ArrayList<URL>();
//根據URL類別,獲取一組要訂閱的路徑
for(String path : toCategoriesPath(url)){
ConcurrentMap<NotifyListener , ChildListener> listeners = zkListeners.get(url);
//如果listeners緩存爲空則創建緩存
if(listeners == null){
zkListeners.putIfAbsent(url , new ConcurrentHashMap<NotifyListener , ChildListener>);
listeners = zkListeners.get(url);
}
ChildListener zkListener = listeners .get(listener);
//如果zkListener緩存爲空則創建緩存
if(zkListener == null){
listeners.putIfAbsent(listener , new ChildListener (){
@Override
public void childChanged(String parentPath , List<String> currentChilds){
ZookeeperRegistry.this.notify(url , listener , toUrlsWithEmpty(url , parentPath , currentChilds));
}
});
zkListener = listeners.get(listener);
}
zkClient.create(path , false);
//訂閱,返回該節點下的子路徑並緩存
List<String> children = zkClient.addChildListener(path , zkListener);
if(children != null){
urls.addAll(toUrlsWithEmpty(url ,path ,children));
}
}
//回調NotifyListener, 更新本地緩存信息
notify(url , listener ,urls);
注意,根據URL中category類別,然後拉取直接子節點的數據進行通知(notify)。
providers 類別:訂閱方會更新本地Directory管理的Invoker服務列表;
routers類別:訂閱方會更新本地路由規則列表;
configuators類別:訂閱方會更新或覆蓋本地動態參數列表。