本文介绍了在zookeeper中创建路径的最有效方式,其中路径的根元素可能存在或可能不存在?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

假设一个路径为/ root / child1 / child2 / child3

想象一下,在zookeeper中可能存在这样的一部分,比如说/ root / child1 / p>

在zookeeper中没有相当于mkdir -p的值;另外,如果任何一个操作失败,ZooKeeper.multi()将失败,所以make path不能真正被烘焙成多重调用。另外,你还可以让其他一些客户端尝试创建相同的路径。



这就是我为创建路径而想出的。我怀疑是否值得检查一个部分是否存在,以保存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();
尝试{
//打扰存在的电话或不是?
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)其他一些客户端可能正在尝试写入相同的路径(并且我们希望避免锁定)。

解决方案

存在的呼叫可以从服务器到客户端进行1次往返。

创建调用具有相同的往返行程,但create是一个写入操作,需要zk集群中服务器之间的更多往返行程,因此create是所以你算法的总时间是,

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

所以 if (!exists())create() vs create()可能会更快。最后它可能没有关系。



如果你想要真的很快,你可以使用async API,这样你就可以创建你的路径的所有组件而不需要等待服务器对1的请求作出回应。

  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){
//等待最后一条路径
success.set(rc == KeeperException.Code.NODEEXISTS ||
rc == KeeperException.Code.OK);
latch.countDown(); $ b $ (String pathElement:pathParts){
path.append(UNIX_FILE_SEPARATOR){

};

StringBuilder path = new StringBuilder();
).append(pathElement);
String pathString = path.toString();
//发送请求以创建路径的所有部分而不等待
//先前调用的结果返回
zooKeeper.create(pathString,null,ZooDefs.Ids.OPEN_ACL_UNSAFE,CreateMode.PERSISTENT,cb);
}
latch.await();
if(!success。 get()){
throw ...
}


Imagine a path "/root/child1/child2/child3"

Imagine in zookeeper that maybe a part of this exists, say "/root/child1"

There is no equivalent of "mkdir -p" in zookeeper; Also, ZooKeeper.multi() will fail if any one operation fails, so a "make path" couldn't really be baked into a multi call. Additionally, you could have some other client trying to make the same path...

This is what I have come up with for creating a path. I wonder if it is even worth checking to see if a part exists or not, to save the round trip of the exists() call.

//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;
        }
    }
}

What would be the most efficient way to do this? Assuming that a) you don't know ahead of time how much of the path already exists and b) some other client might be trying to write the same path (and we want to avoid locking).

解决方案

An exist call can be made with 1 round trip from the server to the client.

A create call has the same round trip, but create is a write operation that entails a couple more round trips between the servers in the zk cluster, so a create is a little more expensive that an exist.

So the total time for your algorithm is,

Time for 1 read op * Probability node already exists + (Time for 1 write op) * (1 - Probability the node already exists).

So either of if(!exist()) create() vs create() could be faster. In the end it probably doesn't matter.

If you want to be really fast, you can use the async api so that you can create all the components of your path without waiting for the server to respond to requests 1 by 1.

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 ...
}

这篇关于在zookeeper中创建路径的最有效方式,其中路径的根元素可能存在或可能不存在?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-11 08:09