본문 바로가기

Etc/Zookeeper

Zookeeper 활용 시나리오 (Recipes And Solutions)

ZooKeeper공식 문서를 보면 Recipes라고, zookeeper를 사용하는 방법에 대해 나와있는 문서가 있다. 이 포스팅에서 그 중 몇가지에 대해 알아보도록 하자.

zookeeper.apache.org/doc/r3.6.2/recipes.html

Barriers

barrier는 분산시스템에서 클라이언트의 집합이 있을 때, 클라이언트가 진행할 수 있는 조건이 충족될때까지 클라이언트의 처리를 차단하는 것, 쉽게 말해서 클라이언트들은 barrier node를 생성하려고 시도하며, barrier node를 생성한 클라이언트만 작업을 수행할 수 있도록 구성하여, 클라이언트 집합에서 한번에 한 클라이언트만 작업을 할 수 있도록 막는 것이다.

pseudo code

  1. Client 는 Zookeeper API인 exist()를 barrier node에 대해 호출하고, watch에 true를 Set한다.
  2. exist()가 false를 리턴하면, Client는 barrier node를 생성하고, 작업을 수행한다.
  3. exist()가 true를 리턴하면, Client는 barrier node에 대한 watch event를 기다린다.
  4. watch 이벤트가 트리거 되면, Client는 barrier를 선점하여 작업을 수행하기 위해 1번으로 돌아간다.

Double Barriers

Double barrier는 클라이언트 집합에 속한 클라이언트들의 작업 시작과 종료를 동기화 하는데 사용할 수 있다.

충분한 클라이언트가 barrier에 join하면, Client들은 자신의 작업을 시작하고, 끝나면 barrier를 빠져나간다.

pseude code

b는 barrier node, p는 client process, x는 Client가 작업시작이 트리거 되는 barrier에 join하는 Client의 최소 수

 

Enter

1. Create a name n = b+"/"p

2. Set watch: exists(b+"/ready",true)

3. Create Child: create(n, EPHEMERAL)

4. L = getChildren(b, false)

5. If fewer children in L than x, wait for watch event

6. else create(b+"/ready", REGULAR)

  1. 진입(Entering)시 모든 프로세스는 ready node를 watch하고, ephemeral 노드를 barrier노드의 child로 생성한다.
  2. 마지막 프로세스를 제외한 각각의 프로세스는 barrier에 들어간뒤에, ready 노드가 생성될 때까지 기다린다.
  3. 마지막 프로세스인 x 번째 노드를 생성하는 프로세스는, 자식 목록에서 x번째 노드를 보고 ready 노드를 생성하여 다른 프로세스를 깨운다
  4. ready node를 watch하고 있던 Process는 모두 일어나서 자신의 작업을 수행한다. (Client 집합의 작업 시작 시점을 동기화)

Leave

1. L = getChildren(b, false)

2. if no children, exist

3. if p is only process node in L, delete(n) and exit

4. if p is the lowest process node in L, wait on highest process node in L

5. else delete(n) if still exists and wait on lowest process node in L

6. goto 1

 

  1. 종료시 ready와 같은 플래그를 사용할 수 없다. 왜냐하면 사라질 노드를 watching하고 있었기 때문 사라질때 노드생성 안대니깐
  2. ephemeral Node를 사용했기 때문에, barrier에 진입한 프로세스는 fail(실패)한 이후에도 올바른 프로세스가 완료되는 것을 방해하지 않는다.
  3. 프로세스가 leave 떠날 준비가 되었으면, 프로세스 노드를 삭제하고, 다른 프로세스가 동일한 작업을 수행할 때 까지 기다린다.
  4. 프로세스들은 exit하는데 그b의 children에 아무 노드가 없을 때,
  5. 근데 효율성을 위해서, 가장 낮은 프로세스(?) 노드를 Ready 플래그로 사용할 수 있다.
  6. 종료가 준비된 모든 다른 프로세스들은 watch 한다 이 lowest 프로세스가 사라지는거를
  7. lowest 프로세스의 소유자는 다른 프로세스 노드 (단순성을 위해 highest노드)가 사라지는지 감시한다.
  8. 이게 의미하는 바는, 각각의 노드 삭제시 단일 프로세스만 깨어난다. 삭제될때 모든 노드를 깨우는 마지막 노드를 제외하고

 

Queues

Zookeeper에서 분산큐 (Distributed queue)를 구현하기 위해서 먼저 큐를 보유할 zNode를 지정해야 한다. 이를 큐노드라고 명명함. 분산된 Client는 데이터를을 queue에 put하는데, create() 메서드를 통해서! pathname은 "queue-"로 끝나게하고, sequence, ephemeral flag를 true로 설정한다.

sequence 플래그가 세팅되면 새로운 pathname은 "_path-to-queue-node_/ queue-X" 형식을 가지며 X는 단조증가하는 숫자이다.

queue에서 삭제를 원하는 client는 getChildren()을 호출하는데, watch를 true로 세팅하고 queue node에, 그리고 가장 낮은 node 부터 처리하기 시작한다. client는 처음 getChildren()에서 얻은 list를 소모할때까지 다른 getChildren()함수를 호출할 필요가 없다.

Queue node에 Children이 없으면 Queue를 읽으려는 Client는 Queue에 데이터가 Put되었다는 Watch알람을 기다린다.

 

Leader Election

 Zookeeper로 Leader Election을 수행하는 간단한 방법은 Client의 목적을 나타내는 zNode를 만들고, 이를 만들 때 SEQUENCE | EPHEMERAL 플래그를 사용하는 것이다.

 이 아이디어는 "/election"과 같은 zNode를 갖는 것이며, 각각의 zNode는 "/election/n_" 자식노드를 SEQUENCE | EPHEMERAL 플래그와 함께 만든다.

 이 때, 시퀀스 번호가 가장 작은 znode를 만든 Client가 리더가 되는 방식으로 Leader Election을 수행한다. 

 추가적으로, 리더의 failure를 감시하여, 현재 리더가 failure된 때 새로운 client가 새로운 leader로 등장하게 하는것이 중요하다. 가장 쉬운 해결책은 모든 Client에서, 현재 smallest znode(리더)를 감시하고, smallest znode가 사라질 때, 새로운 리더(자신이 생성한 zNode가 가장 작은 시퀀스 번호를 갖고 있는지)인지 스스로 체크하는것

 

 위 방법은 현재 리더가 실패하면 다른 모든 프로세스는 알림을 받고 "/ election"에서 getChildren을 실행하여 "/ election"의 현재 하위 목록을 가져오게 되고, 클라이언트 수가 많으면 ZooKeeper 서버가 처리해야하는 작업 수가 급증한다.

 

 이런 오버헤드를 피하기 위해 클라이언트가 갖고있는 znode에서 바로 앞 순서의 zNode만 Watch함으로 써 오버헤드를 줄일 수 있다. 즉 클라이언트가보고있는 znode가 사라 졌다는 알림을 받으면 내 바로 앞에 더 작은 znode가없는 경우 새로운 리더가되고. 이렇게하면 모든 클라이언트가 동일한 znode를 보지 않고, 자기 앞의 한 노드만 보기 때문에, 각 클라이언트에서 시퀀스의 전체 노드가 아니라, 자기 앞의 노드만 보면 되기 때문에 오버헤드를 줄일 수 있다.

 

Pseudo code

Let ELECTION be a path of choice of the application. To volunteer to be a leader:

  1. Create znode z with path "ELECTION/n_" with both SEQUENCE an EPHEMERAL flags;
  2. Let C be the children of "ELECTION", and i be the swquence number of z;
  3. Watch for changes on "ElECTION/n_j", where j is the largest sequence number such that j < i and n_j is a znode in C;

Upon receiving a notification of znode deletion:

  1. Let C be the new set of children of ELECTION;
  2. If z is the smallest node in C, then execute leader procedure;
  3. Otherwise, watch for changes on "ELECTION/n_j", where j is the largest sequence number such that j < i and n_j is a znode in C;

Note that the znode having no preceding znode on the list of children does not imply that the creator of this znode is aware that it is the current leader.

Applications may consider creating a separate znode to acknowledge that the leader has executed the leader procedure.

 

 

'Etc > Zookeeper' 카테고리의 다른 글

Zookeeper Golang Client  (0) 2021.01.03
zookeeper Replication (3 host clustering) 설정하기  (0) 2020.12.22
Zookeeper 설치 및 환경설정  (0) 2020.12.21
Apache zookeeper란?  (0) 2020.12.19