ZooKeeper Watch 回撥事件丟失
- Watch 是一次性的,如果 watch 事件發生了,還想 watch 需要再設定新的watch
- 因為 watch 的一次性,再次註冊 watch 的網路延遲,所以 znode 每次變更不可能都 watch 到
- 一個 watch 物件或者函式/上下文對(pair),只會觸發一次。比如,如果相同的 watch 物件註冊了 exist 和 getData 呼叫在相同檔案,並且檔案已經被刪除,watch 物件只會在檔案被刪除觸發一次
- 當你與一個服務斷開(比如zk服務宕機),你將不會獲得任何 watch,直到連線重連。因此,session 事件將會發送給所有 watch 處理器。使用 session 事件進入一個安全模式:當斷開連線的時候將不會收到任何事件,因此您的程序應該以該模式保守執行
用程式碼表現一下 Watch 回撥事件丟失:
package com.wenniuwuren.zookeeper.curator.watch; import org.apache.curator.framework.CuratorFramework; import org.apache.curator.framework.CuratorFrameworkFactory; import org.apache.curator.framework.recipes.cache.NodeCache; import org.apache.curator.framework.recipes.cache.NodeCacheListener; import org.apache.curator.retry.ExponentialBackoffRetry; import com.wenniuwuren.Constants; /** * Zookeeper之Watcher監聽事件丟失 * * @author wenniuwuren */ public class WatchLost { static String path = "/test/watchlost1"; static CuratorFramework client = CuratorFrameworkFactory.builder().connectString(Constants.ZK_HOST) .retryPolicy(new ExponentialBackoffRetry(1000, 3)).build(); public static void main(String[] args) { try { client.start(); final NodeCache nodeCache = new NodeCache(client, path); nodeCache.start(); if (client.checkExists().forPath(path) == null) client.create().forPath(path, "0".getBytes()); nodeCache.getListenable().addListener(new NodeCacheListener() { @Override public void nodeChanged() throws Exception { if (nodeCache.getCurrentData() == null) { System.out.println("節點被刪除"); } else { System.out.println("節點當前內容為:" + new String(nodeCache.getCurrentData().getData())); } } }); client.setData().forPath(path, "1".getBytes()); client.setData().forPath(path, "2".getBytes()); client.setData().forPath(path, "3".getBytes()); client.setData().forPath(path, "4".getBytes()); client.setData().forPath(path, "5".getBytes()); client.setData().forPath(path, "6".getBytes()); client.setData().forPath(path, "7".getBytes()); client.setData().forPath(path, "8".getBytes()); client.setData().forPath(path, "9".getBytes()); } catch (Exception e) { e.printStackTrace(); } } }
多次的執行結果:
執行結果一:
節點當前內容為:9
節點當前內容為:3
節點當前內容為:4
節點當前內容為:5
節點當前內容為:6
節點當前內容為:7
節點當前內容為:8
節點當前內容為:9
執行結果二:
節點當前內容為:9
節點當前內容為:2
節點當前內容為:3
節點當前內容為:4
節點當前內容為:5
節點當前內容為:6
節點當前內容為:7
節點當前內容為:8
節點當前內容為:9
執行結果三:
節點當前內容為:9
節點當前內容為:3
節點當前內容為:4
節點當前內容為:6
節點當前內容為:7
節點當前內容為:8
節點當前內容為:9
執行幾次,可以看到,並不是每次 client 都是收到 watch 回撥,會漏掉幾次。所以在使用 ZooKeeper Watch 的時候,不能覺得監聽回撥一定會成功,所以在寫程式碼的時候要注意這一點。