2012-03-27 2 views
10

경로 "/ 루트/자식 1/자식 2/child3"경로의 루트 요소가 존재할 수도 있고 없을 수도있는 사육사에서 경로를 만드는 가장 효율적인 방법은 무엇입니까?

어쩌면 이것의 일부가 존재 사육사의 상상을 상상 "에서 mkdir -p의 동등한이 없습니다

"/ 루트/자식 1 "을 말한다 "사육사에서. 또한 하나의 작업이 실패하면 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(); 
     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) 다른 클라이언트가 동일한 경로를 작성하려고 시도하고있을 수 있습니다 (잠금을 피하기를 원합니다).

+0

에 의해 요청 1에 응답하기 위해 서버를 기다리지 않고 경로의 모든 구성 요소를 만들 수 있도록

, 당신은 비동기 API를 할 수 있습니다 인스턴스 변수 경로에 포함 된 내용과 pathParts 매개 변수에 전달되는 내용의 예를 제공 하시겠습니까? 코드에 대한 혼란을 일으키는 코드가 있습니다. –

+0

죄송합니다 - 실수가있었습니다. 이제는 고쳐질 것입니다. – marathon

답변

7

통화가 서버에서 클라이언트로 1 개 라운드 여행과 함께 할 수있을 훨씬 간단 사육사를 사용하게 Netflix's curator 라이브러리를 사용할 수 있습니다.

create 호출은 동일한 왕복 시간을 가지지 만 create는 zk 클러스터의 서버간에 몇 번 왕복을 필요로하는 쓰기 작업이므로 create가 약간 더 비쌉니다.

그래서 알고리즘의 총 시간은 1이 이미 + 존재 연산 * 확률 노드를 읽어

시간입니다 * (시간 1 개 쓰기 연산을위한) (1 - 노드가 이미 존재 확률).

if(!exist()) create()create() 대 중 그러니 빨리 될 수 있습니다. 결국 그것은 중요하지 않습니다. 당신이 정말로 빨리 할 경우 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 ... 
} 
+0

좋은 답변입니다. +1 – kirugan

13

당신은

client.create().withMode(CreateMode.PERSISTENT).forPath("/root/child1/child2/child3", new byte[0]).withACL(ZooDefs.Ids.OPEN_ACL_UNSAFE).creatingParentsIfNeeded(); 
+0

하지만 이것보다 더 효율적입니까 아니면 그냥 숨길 수 있습니까? – marathon

+0

EnsurePath (https://github.com/Netflix/curator/blob/master/curator-client/src/main/java/com/netflix/curator/utils/EnsurePath.java) 및 ZKPaths (https : //github.com/Netflix/curator/blob/master/curator-client/src/main/java/com/netflix/curator/utils/ZKPaths.java) 자신을 위해 결정하십시오. –

+0

같은 번호의 네트워크 호출이지만 더 나쁜 경우 동기화 된 블록이 있기 때문입니다. 사육사들과 함께 원자 경로 생성 호출을 요청하는 티켓을 열어 보겠습니다. 버전 2.9.0을 사용하여 – marathon