Zookeeper客戶端對比選擇_4
Zookeeper客戶端對比選擇
本文思維導圖
使用框架的好處是自帶一套實用的API,但是Zookeeper雖然非常強大,但是社區卻安靜的可怕,版本更新較慢,下面會先從zookeeper原生API的不足說起,然後引出現在流行的開源客戶端工具。
1.原生API
- 1.創建連接的時候是異步的,所以我們在開發的時候需要人工的寫代碼等待創建節點的狀態,如果需要的話。
- 2.連接時無超時重連機制。本人覺得這個非常重要,因為在現實使用中,網絡是不可信的,在創建節點的時候要考慮到網絡的不穩定性。因此,超時重連機制是非常必要的。
- 3.zookeepr的通信是網絡通信,因此在數據通信的時候會消耗一定的網絡IO和帶寬。但zookeeper沒有序列化機制,需要開發者自行開發。
- 4.Watcher註冊一次,觸發後會自動失效。
- 5.不支持遞歸創建樹形節點。這點是比較有用的,類似Linux的命令:
mkdir -p /xxx/xxx/
基於以上的一些不足,引起了業界一些大佬的不滿,因此它們自行開發了一些開源的客戶端工具。比如ZkClient和Curator。對前者簡單介紹,現在使用最多的是後者。
2.ZkClient
2.1 ZkClient概述
ZkClient是Github上一個開源的zk客戶端,由datameer的工程師Stefan Groschupf和Peter Voss一起開發(最仰慕的就是這類大佬,類似Linus那樣,一不爽寫個開源版本(git)出來...)
- 解決session會話超時重連。
- Watcher反復註冊。
- 簡化開發api。
當然還有很多的很多修改的功能,使用也很簡單,但是社區不活躍,連api文檔都不完善,對於我們來說只能看源碼來開發應用了,也略有麻煩的。有興趣的開源上github看看。 https://github.com/sgroschupf/zkclient
2.2 ZkClien API
- 創建客戶端
ZkClient zkclient = new ZkClient("192.168.17.128:2181,192.168.17.129:2181,192.168.17.130:2181",5000);
- 創建節點
zkclient.create(path, data, CreateMode.PERSISTENT);
- 刪除節點
zkclient.delete(path);
- 獲取子節點
zkclient.getChildren(path);
- 關閉客戶端
zkclient.close();
- 讀節點數據
zkclient.readData(path);
- 判斷節點是否存在
zkclient.exists(path);
3.Curator
3.1 Curator概述
Curator是Apache基金會的頂級項目之一。Apache基金會就類似萬能儲備室,把全球頂級的開源項目收納其中,造福一方百姓啊。
- 下面是Curator對比原生zk的API和ZkClient比較重要的完善點:
- 解決session會話超時重連。
- Watcher反復註冊。
- 簡化開發api。
- 遵循Fluent風格Api規範。
- NodeExistsException異常處理。
- ......
3.2 Curator API介紹
- 創建會話
- 1.使用CuratorFrameworkFactory工廠的兩個靜態方法創建客戶端
2.Start()方法啟動
RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
client = CuratorFrameworkFactory.builder()
.connectString("localhost:2181,localhost:2182")
.sessionTimeoutMs(10000).retryPolicy(retryPolicy)
.namespace("base").build();
client.start();1.重試策略(實現接口RetryPolicy可以自定義重試策略)
boolean allowRetry(int retryCount, long elapsedTimeMs, RetrySleeper sleeper)
2.默認四種重試策略: Exponential BackoffRetry、RetryNTimes、RetryOneTime、
RetryUntilElapsed- 2.1 ExponentialBackoffRetry
ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries)
ExponentialBackoffRetry(int baseSleepTimeMs, int maxRetries, int maxSleepMs)
當前應該sleep的時間:
baseSleepTimeMs * Math.max(1, random.nextInt(1 << (retryCount + 1)))
- 2.2 RetryNTimes
RetryNTimes(int n, int sleepMsBetweenRetries)
- 2.3 RetryOneTime
RetryOneTime(int sleepMsBetweenRetry)
2.4 RetryUntilElapsed
RetryUntilElapsed(int maxElapsedTimeMs, int sleepMsBetweenRetries)
- 3.Fluent風格的API
- 定義:一種面向對象的開發方式,目的是提高代碼的可讀性
- 實現方式?通過方法的級聯或者方法鏈的方式實現
例子:
client = CuratorFrameworkFactory.builder() .connectString("localhost:2181,localhost:2182") .sessionTimeoutMs(10000).retryPolicy(retryPolicy) .namespace("base").build();
- 4.常用API
4.1創建節點
public void createNode(String path, byte[] data) throws Exception { client.getZookeeperClient().getZooKeeper().addAuthInfo("digest", "test:123456".getBytes()); client.create().creatingParentsIfNeeded() .withMode(CreateMode.PERSISTENT).withACL(Ids.CREATOR_ALL_ACL) .forPath(path, data); }
4.2刪除節點
public void deleteNode(String path, int version) throws Exception { client.delete().guaranteed().deletingChildrenIfNeeded().withVersion(version) .inBackground(new DeleteCallBack()).forPath(path); }
4.3讀取節點
public void readNode(String path) throws Exception { byte[] data = client.getData().inBackground(new DeleteCallBack()).forPath(path); System.out.println(path + "的數據:" + new String(data)); }
4.4更新節點數據
public void updateNode(String path, byte[] data, int version) throws Exception { client.setData().withVersion(version).inBackground(new DeleteCallBack()).forPath(path, data); }
4.5獲取子節點
public void getChildren(String path) throws Exception { List<String> children = client.getChildren().usingWatcher(new WatcherTest()).forPath("/test"); for (String pth : children) { System.out.println("child=" + pth); } }
4.6為節點添加監聽
- NodeCache
- 監聽數據節點的內容變更
- 監聽節點的創建,即如果指定的節點不存在,則節點創建後,會觸發這個監聽
- PathChildrenCache
- 監聽指定節點的子節點變化情況
包括新增子節點,子節點數據變更和子節點刪除
public void addNodeDataWatcher(String path) throws Exception { final NodeCache nodeC = new NodeCache(client, path); nodeC.start(true); nodeC.getListenable().addListener(new NodeCacheListener() { public void nodeChanged() throws Exception { String data = new String(nodeC.getCurrentData().getData()); System.out.println("path=" + nodeC.getCurrentData().getPath() + ":data=" + data); } }); }
4.7異步回調
inBackground()
inBackground(Object context)
inBackground(BackgroundCallback callback)
inBackground(BackgroundCallback callback, Object context)
inBackground(BackgroundCallback callback, Executor executor)
inBackground(BackgroundCallback callback, Object context, Executor executor)
Curator的回調與zk的原生異步api相同,多了一個線程池,用於執行回調。
異步操作事件狀態:event.getType()
異步操作事件狀態碼:event.getResultCode()
以上就是Curator常用的API,都是利用這些API來進行更加復雜的應用開發的,比如分布式鎖,集群管理等應用。
4.小結
好的開源工具解放我們的開發,但是不要在其中迷失,還要深入的了解其中的設計原理,不能只是調用API,要學習人家的思想,這樣才能跟隨大神的腳步,提升自己的實力。
Zookeeper客戶端對比選擇_4