ZooKeeper Watch 回調事件丟失

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 的時候,不能覺得監聽回調一定會成功,所以在寫代碼的時候要注意這一點。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章