zookeeper 노드를 만들어 보자

이번시간엔 주키퍼의 노드를 만들어 보자
일단 주키퍼 예제는 여기 있다.
주키퍼 설치는 여기
그냥 간단하게 노드 한개만 만들어 볼 예정이다.

  public static void main(String[] args) throws IOException {
    String host = "wonwoo.ml:18813,wonwoo.ml:18815,wonwoo.ml:18819";
    String rootNode = "/zk_test";
    String childNode = "/zk_test/netty2";
    String data = "http://localhost:9091";
    ZookeeperWatcher zookeeperWatcher = new ZookeeperWatcher(host, rootNode, childNode, data);
    zookeeperWatcher.make();
    zookeeperWatcher.run();

  }

host는 주키퍼가 설치 되어 있는 서버이고 root 노드는 말그대로 root노드이다. childNode는 root의 child를 의미한다.
그리고 노드의 남길 data를 정의했다.
주키퍼는 비동기 콜백 형태로 되기 때문에 쓰레드를 락 걸고 했다.

public class ZookeeperWatcher implements Watcher, AsyncCallback.StringCallback {

  private ZooKeeper zooKeeper;
  private String rootNode;
  private String childNode;
  private String data;
  boolean dead = true;

  ZookeeperWatcher(String hostPort, String rootNode, String childNode, String data) throws IOException {
    this.rootNode = rootNode;
    this.childNode = childNode;
    this.data = data;
    zooKeeper = new ZooKeeper(hostPort, 6000, this);
  }

  public void make() {
    zooKeeper.create(rootNode, "root".getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT, this, "root");
  }

  @Override
  public void process(WatchedEvent event) {

  }

  @Override
  public void processResult(int rc, String path, Object ctx, String name) {
    KeeperException.Code code = KeeperException.Code.get(rc);
    if (code == KeeperException.Code.OK) {
      System.out.println(code);
      if ("root".equals(ctx)) {
        zooKeeper.create(childNode, data.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.EPHEMERAL, this, null);
      }
    } else {
      dead = false;
      closing();
    }
  }

  public void run() {
    try {
      synchronized (this) {
        while (dead) {
          wait();
        }
      }
    } catch (InterruptedException e) {
    }
  }

  public void closing() {
    synchronized (this) {
      notifyAll();
    }
  }
}

나머지는 나중에 더 살펴보고 이번시간엔 make와 processResult를 알아 볼 것이다. 그냥 대충 만들었다.
make 함수의 zooKeeper.create는 아시다시피 노드를 생성 하는 것이다.
여기서 중요한건 노드가 생성한다고 하면 callback으로 성공인지 실패인지 등등 알려준다.
그게 바로 processResult 함수이다. 성공인지 실패인 알 수 있다.
그리고 노드를 만들 때 영원히 노드를 남길 것인지 아니면 세션이 있을 때만 남길 것인지 정할 수 있다.
create할때 CreateMode.PERSISTENT 속성을 넣으면 영원히
CreateMode.EPHEMERAL 속성은 해당 세션이 살아 있을 경우에 지속된다.
한번 테스트 해보자
main를 돌려보면 zk_test와 그 자식 netty2가 생겨났을 것이다.
zk_test에는 root라는 data가 netty2에는 localhost:9091 데이터가 생성 된 것을 볼 수 있다.
그 다음에는 netty2라는 노드는 세션이 살아 있을 때만 생성 했으니 세션이 끊어 버리면 사라질 것으로 예상된다.
한번 종료해보자
그럼 netty2는 사라졌다. 한 5초 이내로 사라진다. 아주 바로는 사라지지 않는다.
이것으로 주키퍼의 node생성에 대해 알아봤다.
나중에는 vertx나 netty를 연동해서 실제 서버가 잘 돌고 있는지 알아볼 예정이다.
언제가 될지는…

주키퍼 설치 및 설정

주키퍼 설치 및 설정

주키퍼를 설치 해보자. 다운로드 여기서 다운 받으면 되겠다

압축을 풀고 원하는 디렉토리에 넣어두자. 필자는 /usr/local/에 넣어 두었다.
${home}/conf/zoo.cfg 파일이 주키퍼 설정 파일이다.

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper1
clientPort=2184

설정을 저장하자.
서버를 실행시켜보자!

./bin/zkServer.sh start

JMX enabled by default
Using config: /usr/local/zookeeper1/bin/../conf/zoo.cfg
Starting zookeeper ... STARTED

주키퍼 클라이언트를 이용해서 접속해보자!

./bin/zkCli.sh -server localhost:2184

접속이 완료되었다.
간단하게 노드를 만들어보자.

[zk: localhost:2184(CONNECTED) 0] create /zoo_test my_data
Created /zoo_test

만들어진 노드를 확인해보자

[zk: localhost:2184(CONNECTED) 1] ls /
[zoo_test, zookeeper]

잘 만들어져 있다.
정보도 한번 보자.

[zk: localhost:2184(CONNECTED) 2] get /zoo_test
my_data
cZxid = 0x500000007
ctime = Wed Mar 02 08:37:55 UTC 2016
mZxid = 0x500000007
mtime = Wed Mar 02 08:37:55 UTC 2016
pZxid = 0x500000007
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0

다음은 replication 설정을 해보자
세개의 주키퍼가 필요하므로 세개를 복사하자.
필자는 이렇게 했다.
/usr/local/zookeeper1
/usr/local/zookeeper2
/usr/local/zookeeper3
그리고 설정을 바꿔줘야한다.
다시 zoo.cfg 파일을 열어서 아래와 같이 바꾸자.

/usr/local/zookeeper1

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper1
clientPort=2184
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

/usr/local/zookeeper2

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper2
clientPort=2185
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

/usr/local/zookeeper3

tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/zookeeper3
clientPort=2186
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

아래의 세줄이 추가 되었고 디렉토리가 변경되었다.
3개의 주키퍼 모두 바꾸자! 디렉토리는 각기 다르게! 물리적으로 서버가 같다면 포트를 나눠줘야한다.
2888 포트는 각각의 통신하기 위한 포트 3888은 마스터를 선출하기 위한 노드라 한다.
server.1,server.2,server.3 의 숫자는 /var/zookeeper1/myid의 값과 동일해야된다.

cat /var/zookeeper1/myid
1
cat /var/zookeeper2/myid
2
cat /var/zookeeper3/myid
3

세개의 노드를 실행해야된다.
귀찮다.
스크립트로 대충 만들었다

#!/bin/bash

param=$1

ZOO1_HOME="/usr/local/zookeeper1/"
ZOO2_HOME="/usr/local/zookeeper2/"
ZOO3_HOME="/usr/local/zookeeper3/"

case $param in
  start)
    $ZOO1_HOME/bin/zkServer.sh start
    $ZOO2_HOME/bin/zkServer.sh start
    $ZOO3_HOME/bin/zkServer.sh start

    ;;
  stop)
    $ZOO1_HOME/bin/zkServer.sh stop
    $ZOO2_HOME/bin/zkServer.sh stop
    $ZOO3_HOME/bin/zkServer.sh stop
    ;;
  restart)
    $0 stop
    sleep 1
    $0 start
    ;;
  *)
   echo  "Usage: $0 {start|stop|restart}"
esac

이제 실행해보자!
잘된다!
다시 접속해보자!

./bin/zkCli.sh -server localhost:2184

그리도 노드를 한개더 생성해보자

[zk: localhost:2184(CONNECTED) 0] create /test test
Created /test
[zk: localhost:2184(CONNECTED) 0] ls /

test가 있는 걸 확인 후 빠져나오자 quit

./bin/zkCli.sh -server localhost:2185

이번엔 2185로 접속해보자

[zk: localhost:2185(CONNECTED) 0] ㅣls /

test가 있는걸 확인 할 수 있다.

2186 포트는 마찬가지로 추가 되어있을 것이다.

별도로 주키퍼 관리할 수 있는 관리자 화면을 누군가가 만들었다.
클로저로 만들었으니 클로저를 설치하자!
주키퍼웹UI