10

想象一个路径“/root/child1/child2/child3”

想象在 zookeeper 中可能存在其中的一部分,比如“/root/child1”

zookeeper 中没有等效的“mkdir -p”;此外,如果任何一个操作失败,ZooKeeper.multi() 将失败,因此“制作路径”不能真正融入到多重调用中。此外,您可能有其他一些客户端尝试创建相同的路径...

这就是我想出的创建路径的方法。我想知道是否值得检查某个部分是否存在,以节省 exists() 调用的往返行程。

//String[] pathParts new String[] { "root", "child1", "child2", "child3" };

public void savePath(String[] pathParts) {
    if (zooKeeper.exists(pathString, false) != null) return;
    StringBuilder path = new StringBuilder();
    for (String pathElement : pathParts) {
        path.append(UNIX_FILE_SEPARATOR).append(pathElement);
        String pathString = path.toString();
        try {
            //bother with the exists call or not?
            if (zooKeeper.exists(pathString, false) == null) {
                zooKeeper.create(pathString, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (KeeperException e) {
            if (e.code() != KeeperException.Code.NODEEXISTS)
                throw e;
        }
    }
}

最有效的方法是什么?假设 a) 您事先不知道已经存在多少路径,并且 b) 其他一些客户端可能正在尝试编写相同的路径(并且我们希望避免锁定)。

4

2 回答 2

13

您可以使用Netflix 的 curator库,它使 Zookeeper 的使用更加简单

client.create().withMode(CreateMode.PERSISTENT).forPath("/root/child1/child2/child3", new byte[0]).withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE).creatingParentsIfNeeded();
于 2012-03-28T05:20:55.567 回答
7

可以通过从服务器到客户端的 1 次往返来进行现有调用。

create 调用具有相同的往返行程,但 create 是一个写入操作,需要在 zk 集群中的服务器之间进行多次往返,因此 create 比存在的成本要高一些。

所以你的算法的总时间是,

1 次读取操作的时间 * 概率节点已经存在 +(1 次写入操作的时间)*(1 - 节点已经存在的概率)。

所以任何一个if(!exist()) create()vscreate()都可以更快。最后可能没关系。

如果你想真的很快,你可以使用 async api,这样你就可以创建路径的所有组件,而无需等待服务器逐个响应请求。

final AtomicBoolean success = new AtomicBoolean(false);
final CountdownLatch latch = new CountdownLatch(1);
StringCallback cb = new StringCallback() {
    processResult(int rc, String path, Object ctx, String name) {
        if(name.equals(pathString ) {
            //wait for the last path
            success.set(rc == KeeperException.Code.NODEEXISTS ||
                        rc == KeeperException.Code.OK);
            latch.countDown();
        }
    }
};

StringBuilder path = new StringBuilder();
for (String pathElement : pathParts) {
    path.append(UNIX_FILE_SEPARATOR).append(pathElement);
    String pathString = path.toString();
    //send requests to create all parts of the path without waiting for the
    //results of previous calls to return
    zooKeeper.create(pathString, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, cb);
}
latch.await();
if(!success.get()) { 
    throw ...
}
于 2012-03-31T03:38:08.367 回答