下面我們來看下開源dubbo推薦的業界成熟的zookeeper做爲註冊中心, zookeeper是hadoop的一個子項目是分佈式系統的可靠協調者,他提供了配置維護,名字服務,分佈式同步等服務。對於zookeeper的原理本文檔不分析,後面有時間在做專題。
zookeeper註冊中心
Zookeeper對數據存儲類似linux的目錄結構,下面給出官方文檔對dubbo註冊數據的存儲示例
假設讀者對zookeeper有所瞭解,能夠搭建zookeeper服務,其實不瞭解也沒關係,谷歌百度下分分鐘搞起。
作爲測試調試dubbo,我是在本地起的zookeeper
指定zookeeper配置文件地址
配置文件中兩個關鍵參數:
dataDir zookeeper存儲文件的地址
clientPort 客戶端鏈接的端口號
Dubbo服務提供者配置
<dubbo:registry protocol=”zookeeper” address="127.0.0. 1:2181" />
<beanid="demoService" class="com.alibaba.dubbo.demo.provi der.DemoServiceImpl"/>
<dubbo:serviceinterface="com.alibaba.dubbo.demo.DemoServi ce" ref="demoService"/>
除了配置註冊中心的,其他都一樣
Dubbo服務消費者配置
<dubbo:registry protocol=”zookeeper” address="127.0.0. 1:2181" />
<dubbo:referenceid="demoService"interface="com.alibaba.dubbo.demo.DemoService"/>
除了配置註冊中心的,其他都一樣
客戶端獲取註冊器
服務的提供者和消費者在RegistryProtocol利用註冊中心暴露(export)和引用(refer)服務的時候會根據配置利用Dubbo的SPI機制獲取具體註冊中心註冊器
Registry registry = registryFactory.getRegistry(url);
這裏的RegistryFactory是ZookeeperRegistryFactory看如下工廠代碼
public class ZookeeperRegistryFactory extends AbstractRegistryFactory {
public Registry createRegistry(URL url) {
return new ZookeeperRegistry(url, zookeeperTransporter);
}
}
這裏創建zookeepr註冊器ZookeeperRegistry
ZookeeperTransporter是操作zookeepr的客戶端的工廠類,用來創建zookeeper客戶端,這裏客戶端並不是zookeeper源代碼的自帶的,而是採用第三方工具包,主要來簡化對zookeeper的操作,例如用zookeeper做註冊中心需要對zookeeper節點添加watcher做反向推送,但是每次回調後節點的watcher都會被刪除,這些客戶會自動維護了這些watcher,在自動添加到節點上去。
接口定義:
@SPI("zkclient")
public interface ZookeeperTransporter {
@Adaptive({Constants.CLIENT_KEY, Constants.TRANSPORTER_KEY})
ZookeeperClient connect(URL url);
}
默認採用zkClient, dubbo源碼集成兩種zookeeper客戶端,除了zkClient還有一個是curator
ZookeeperRegistry註冊器的實現
1.構造器利用客戶端創建了對zookeeper的連接,並且添加了自動回覆連接的監聽器。
zkClient = zookeeperTransporter.connect(url);
zkClient.addStateListener(new StateListener() {
public void stateChanged(int state) {
if (state ==RECONNECTED)
recover();
}
});
2.註冊url就是利用客戶端在服務器端創建url的節點,默認爲臨時節點,客戶端與服務端斷開,幾點自動刪除
zkClient.create(toUrlPath(url),url.getParameter(Constants.DYNAMIC_KEY,true));
3.取消註冊的url,就是利用zookeeper客戶端刪除url節點
zkClient.delete(toUrlPath(url));
4. 訂閱url, 功能是服務消費端訂閱服務提供方在zookeeper上註冊地址,這個功能流程跟DubboRegister不一樣, DubboRegister是通過Dubbo註冊中心實現SimpleResgiter在註冊中心端,對url變換、過濾篩選然後將獲取的provierUrl(提供者ulr)利用服務消費者暴露的服務回調在refer。
由於這裏註冊中心採用的是zookeeper,zookeeper不可能具有dubbo的業務邏輯,這裏對訂閱的邏輯處理都在消費服務端訂閱的時候處理。
1) 對傳入url的serviceInterface是*代表訂閱url目錄下所有節點即所有服務,這個註冊中心需要訂閱所有
2) 如果指定了訂閱接口通過toCategoriesPath(url)轉換需要訂閱的url
如傳入url consumer://10.33.37.8/com.alibaba.dubbo.demo.DemoService?application=demo-consumer&category=providers,configurators,routers&dubbo=2.5.4-SNAPSHOT&interface=com.alibaba.dubbo.demo.DemoService&methods=sayHello&pid=4088&side=consumer×tamp=1417405597808
轉換成urls
/dubbo/com.alibaba.dubbo.demo.DemoService/providers,/dubbo/com.alibaba.dubbo.demo.DemoService/configurators, /dubbo/com.alibaba.dubbo.demo.DemoService/routers
3) 設配傳入的回調接口NotifyListener,轉換成dubbo對zookeeper操作的ChildListener
4)以/dubbo/com.alibaba.dubbo.demo.DemoService/providers爲例創建節點zkClient.create(path, false);
但是一般情況下如果服務提供者已經提供服務,那麼這個目錄節點應該已經存在,Dubbo在Client層屏蔽掉了創建異常。
5) 以/dubbo/com.alibaba.dubbo.demo.DemoService/providers爲例給節點添加監聽器,返回所有子目錄
List<String> children = zkClient.addChildListener(path, zkListener);
if (children !=null) {urls.addAll(toUrlsWithEmpty(url, path,hildren));}
toUrlsWtihEmpty用來配置是不是需要訂閱的url,是加入集合
6) 主動根據得到服務提供者urls回調NotifyListener,引用服務提供者生成invoker可執行對象
5. 取消訂閱url, 只是去掉url上的註冊的監聽器