Groovy で ZooKeeper を組み込み実行
以前、Groovy で Apache ZooKeeper を使う にて ZooKeeper のクライアントを Groovy スクリプトで実装しましたが、今回は ZooKeeper のサーバーを Groovy で組み込み実行してみました。
サンプルソースは http://github.com/fits/try_samples/tree/master/blog/20131109/
ZooKeeper 組み込み実行スクリプト
ZooKeeper を組み込み実行するための単純なスクリプトは下記のようになります。 第一引数に ZooKeeper 設定ファイルのパスを指定して実行します。
zk_run.groovy
@Grapes([ @Grab("org.apache.zookeeper:zookeeper:3.4.5"), @GrabExclude("com.sun.jmx#jmxri"), @GrabExclude("com.sun.jdmk#jmxtools"), @GrabExclude("javax.jms#jms") ]) import org.apache.zookeeper.server.quorum.QuorumPeerMain new QuorumPeerMain().initializeAndRun(args) // 単独実行しかしないのであれば下記でも可 // org.apache.zookeeper.server.ZooKeeperServerMain.main(args)
複製モードで実行しないのであれば、QuorumPeerMain の代わりに ZooKeeperServerMain を直接使う方法もあります。
また、ログ出力を行うには ZooKeeper の conf ディレクトリにある log4j.properties
ファイルを上記スクリプトと同じディレクトリへ配置しておきます。
単独モード実行
それでは単独モードで実行してみます。
まずは、必要最小限の設定を記載した ZooKeeper の設定ファイルを用意しておきます。
u0/zoo.cfg (設定ファイル)
dataDir=u0/tmp/zookeeper clientPort=2181
設定ファイルへのパスを引数にして zk_run.groovy を実行すれば ZooKeeper が起動します。
実行
> groovy zk_run.groovy u0/zoo.cfg 2013-11-09 10:57:13,730 [myid:] - INFO [main:QuorumPeerConfig@101] - Reading configuration from: u0/zoo.cfg 2013-11-09 10:57:13,746 [myid:] - INFO [main:DatadirCleanupManager@78] - autopurge.snapRetainCount set to 3 2013-11-09 10:57:13,746 [myid:] - INFO [main:DatadirCleanupManager@79] - autopurge.purgeInterval set to 0 2013-11-09 10:57:13,746 [myid:] - INFO [main:DatadirCleanupManager@101] - Purge task is not scheduled. 2013-11-09 10:57:13,746 [myid:] - WARN [main:QuorumPeerMain@113] - Either no config or no quorum defined in config, running in standalone mode ・・・
zkCli
コマンドを使って接続できます。
> zkCli Connecting to localhost:2181 ・・・
複製モード実行
次に複製モードの実行を試してみます。
複製モード用の設定ファイル
まずは設定ファイルを用意します。 単独実行と比べて initLimit、syncLimit、server 設定の追加が必要です。
server 設定は下記のようなフォーマットとなっており、ポート番号を 2つ指定する必要があります。 (サーバー同士の接続ポートとリーダー選出に使用するポートのようです)
server.<サーバー番号>=<サーバー名>:<ポート番号1>:<ポート番号2>
今回は同一ホスト上で実行するのでポート番号をそれぞれ分けています。
なお、ZooKeeper の複製モードは最低 3サーバー構成で実行するようです。
2サーバー構成で実行すると WARN ログ No server failure will be tolerated. You need at least 3 servers.
が出力されます。
u1/zoo.cfg (設定ファイル1)
dataDir=u1/tmp/zookeeper clientPort=2181 initLimit=10 syncLimit=5 server.1=localhost:2888:3888 server.2=localhost:2889:3889 server.3=localhost:2890:3890
u2/zoo.cfg (設定ファイル2)
dataDir=u2/tmp/zookeeper clientPort=2182 initLimit=10 syncLimit=5 server.1=localhost:2888:3888 server.2=localhost:2889:3889 server.3=localhost:2890:3890
u3/zoo.cfg (設定ファイル3)
dataDir=u3/tmp/zookeeper clientPort=2183 initLimit=10 syncLimit=5 server.1=localhost:2888:3888 server.2=localhost:2889:3889 server.3=localhost:2890:3890
myid ファイル
更に、複製モードではサーバー番号を設定した myid
ファイルを予め配置しておく必要があります。
myid
ファイルは設定ファイルの dataDir
で指定したディレクトリへ配置します。
u1/tmp/zookeeper/myid
1
u2/tmp/zookeeper/myid
2
u3/tmp/zookeeper/myid
3
実行
サーバーを順次実行します。
他のサーバーを起動していない状態では ConnectException の WARN ログが出力されますが、全サーバーを起動すると出なくなります。
サーバー1 実行
> groovy zk_run.groovy u1/zoo.cfg 2013-11-09 20:53:09,157 [myid:] - INFO [main:QuorumPeerConfig@101] - Reading configuration from: u1/zoo.cfg ・・・ 2013-11-09 20:53:10,390 [myid:1] - WARN [WorkerSender[myid=1]:QuorumCnxManager@368] - Cannot open channel to 2 at election address localhost/127.0.0.1:3889 java.net.ConnectException: Connection refused: connect at java.net.DualStackPlainSocketImpl.waitForConnect(Native Method) ・・・ ・・・ 2013-11-09 21:02:04,636 [myid:1] - INFO [WorkerReceiver[myid=1]:FastLeaderElection@542] - Notification: 2 (n.leader), 0x0 (n.zxid), 0x1 (n.round), LOOKING (n.state), 3 (n.sid), 0x3 (n.peerEPoch), FOLLOWING (my state)
サーバー2 実行
> groovy zk_run.groovy u2/zoo.cfg ・・・ 2013-11-09 21:02:04,948 [myid:2] - INFO [LearnerHandler-/127.0.0.1:49289:LearnerHandler@419] - Sending snapshot last zxid of peer is 0x0 zxid of leader is 0x400000000sent zxid of db as 0x400000000
サーバー3 実行
> groovy zk_run.groovy u3/zoo.cfg ・・・ 2013-11-09 21:02:04,948 [myid:3] - INFO [QuorumPeer[myid=3]/0:0:0:0:0:0:0:0:2183:FileTxnSnapLog@240] - Snapshotting: 0x400000000 to u3/tmp/zookeeper/version-2/snapshot.400000000