docker-compose で zookeeper のクラスタを立ち上げて動作確認する - Qiita の続き。今度はフェイルオーバーを試してみる。
leader/follower の確認
まず、クラスタ内のどのコンテナが leader でどのコンテナが follower なのかを確認できるようしておく。
基本的には、各プロセスが LISTEN してる TCP ポートに srvr
という文字列を送ると、そのプロセスの Mode を取得することができる。
$ echo srvr | docker exec -i zookeeper_zoo1_1 nc localhost 2181
Zookeeper version: 3.4.9-1757313, built on 08/23/2016 06:50 GMT
Latency min/avg/max: 0/2/35
Received: 73
Sent: 72
Connections: 3
Outstanding: 0
Zxid: 0x50000000c
Mode: follower
Node count: 5
情報量が多いので、3 つのコンテナに上記のリクエストを投げて Mode 部分だけ表示するシェルを書いた。
$ cat cluster-status.sh
for i in `seq 1 3`; do
container_name=zookeeper_zoo${i}_1
echo -n "${container_name} -> "
echo srvr | docker exec -i ${container_name} nc localhost 2181 | grep Mode | cut -d " " -f2
done
今は 2 番目のコンテナ zoo2 が leader になっていることが分かる。
$ sh cluster-status.sh
zookeeper_zoo1_1 -> follower
zookeeper_zoo2_1 -> leader
zookeeper_zoo3_1 -> follower
1 台落としてみる
この状態で、leader を停止してみる。
$ docker-compose pause zoo2
Pausing zookeeper_zoo2_1 ... done
leader が zoo3 に変更された。
$ sh cluster-status.sh
zookeeper_zoo1_1 -> follower
zookeeper_zoo2_1 -> Error response from daemon: Container zookeeper_zoo2_1 is paused, unpause the container before exec
zookeeper_zoo3_1 -> leader
zoo1 でも zoo3 でも get /helloworld
できる。
$ docker exec -ti zookeeper_zoo1_1 bin/zkCli.sh -server zookeeper_zoo1_1 get /helloworld
(略)
this is test updated
(略)
$ docker exec -ti zookeeper_zoo3_1 bin/zkCli.sh -server zookeeper_zoo3_1 get /helloworld
(略)
this is test updated
(略)
set /helloworld "written while zoo2 is down"
しておく。
$ docker exec -ti zookeeper_zoo1_1 bin/zkCli.sh -server zookeeper_zoo1_1 set /helloworld "written while zoo2 is down"
(略)
もう 1 台落としてみる
さらにもう 1 台落としてみる。
$ docker-compose pause zoo1
Pausing zookeeper_zoo1_1 ... done
zookeper クラスタは過半数のメンバーが生きていないと機能しないので、zoo3 での get /helloworld
は失敗する。
$ docker exec -ti zookeeper_zoo3_1 bin/zkCli.sh get /helloworld
(略)
2017-01-12 06:19:10,409 [myid:] - INFO [main-SendThread(localhost:2181):ClientCnxn$SendThread@1158] - Unable to read additional data from server sessionid 0x0, likely server has closed socket, closing socket connection and attempting reconnect
Exception in thread "main" org.apache.zookeeper.KeeperException$ConnectionLossException: KeeperErrorCode = ConnectionLoss for /helloworld
at org.apache.zookeeper.KeeperException.create(KeeperException.java:99)
at org.apache.zookeeper.KeeperException.create(KeeperException.java:51)
at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:1212)
at org.apache.zookeeper.ZooKeeper.getData(ZooKeeper.java:1241)
at org.apache.zookeeper.ZooKeeperMain.processZKCmd(ZooKeeperMain.java:725)
at org.apache.zookeeper.ZooKeeperMain.processCmd(ZooKeeperMain.java:599)
at org.apache.zookeeper.ZooKeeperMain.run(ZooKeeperMain.java:362)
at org.apache.zookeeper.ZooKeeperMain.main(ZooKeeperMain.java:290)
cluster-stautus.sh でも残ったコンテナ zoo3 の Mode が表示できなくなった。
$ sh cluster-status.sh
zookeeper_zoo1_1 -> Error response from daemon: Container zookeeper_zoo1_1 is paused, unpause the container before exec
zookeeper_zoo2_1 -> Error response from daemon: Container zookeeper_zoo2_1 is paused, unpause the container before exec
zookeeper_zoo3_1 ->
復旧させてみる
zoo1, zoo2 の一時停止を解除。
$ docker-compose unpause zoo1 zoo2
Unpausing zookeeper_zoo2_1 ... done
Unpausing zookeeper_zoo1_1 ... done
どのノードでも get /helloworld
できるようになった。さらに、zoo2 が落ちていた間に更新されたデータが zoo2 にも反映されていることも分かる。
$ docker exec -ti zookeeper_zoo1_1 bin/zkCli.sh get /helloworld
(略)
written while zoo2 is down
(略)
$ docker exec -ti zookeeper_zoo2_1 bin/zkCli.sh get /helloworld
(略)
written while zoo2 is down
(略)
$ docker exec -ti zookeeper_zoo3_1 bin/zkCli.sh get /helloworld
(略)
written while zoo2 is down
(略)
まとめ
zookeeper クラスタのフェイルオーバーの基本的な挙動を確認することができた。
クラスタ内の過半数より少ないサーバーが落ちてもサービス継続できるところと、一度落ちてしまったサーバーを再度クラスタに参加させるのが簡単そうなところが、よさそうに思った。
より詳しい内部的な仕様を知ってみたいというのと、Hadoop本読書会 - 13章 ZooKeeper - 大規模分散技術勉強会 in 名古屋 に書いてあるような watcher とか他の機能もそのうち試してみたい。