どぅーちゅいむーにー

これ、Twitterでよくね?という日々の記録かも

クラスタの構築

前回のエントリの最後に「Programmers Guideをみると、クライアントプログラムなどの作成方法などが解説されていますが、とりあえず今回は HBase のほうに進むということで、ZooKeeper についての話はいったんここで終わります。」なんて書きましたが、HBase のクラスタ環境を構築するためにはどうも ZooKeeper もクラスタ環境になっている必要があるようなので、ZooKeeper をクラスタ化してみます。
設定については、前回(d:id:k155e1:20100420:1271757128)を参照してください。


マニュアルでいうと Running Replicated ZooKeeper あたりからでしょうか。


HBase のところで出てきますが、HBase をクラスタで動作させる場合、ZooKeeper Quorum を事前に起動させておく必要があります(HDFS もですが)。
で、Quorum って何?という感じだったのですが、ZooKeeper のマニュアルにこういう一文がありました。

A replicated group of servers in the same application is called a quorum.

ちなみに、辞典をひくと「定」とか「数」とかいうらしい(ほんとか?)。余計にわけがわからなくなってきた。
まぁ、それはいいとして、とりあえず同一アプリケーション内のサーバグループ、ということでしょうか。

同一 quorum に所属するサーバは同一の設定を持つ、という定義になるようです。
というより、同一の設定をもつ ZooKeeper のサーバが1つのグループであり、それを quorum と呼ぶ、というほうが正しい?
サンプルとなる記述は以下。

tickTime=2000
dataDir=/var/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=zoo1:2888:3888
server.2=zoo2:2888:3888
server.3=zoo3:2888:3888

ドキュメントではここで initLimit と syncLimit の説明をしています。
単位は tickTime になるようで、上記設定の場合、tickTime の単位はミリ秒のため、1 tickTime は 2秒、ということは、initLimit は 5 × 2秒の 10秒、syncLimit は 2 × 2秒の 4秒という感じだそうです。
server.Xは ZooKeeper が起動しているサーバを記述する感じで。
サーバ名(と思われる)のうしろの 2888 と 3888 はポート番号で、前のポート(2888)は他のサーバと接続するために使われるらしい。後者のほうは(quorumにおける?)リーダーを決めるための通信に使われるっぽいが、よくわかりません。
というわけで、今回の実験環境だとこんな感じでしょうか。

tickTime=2000
dataDir=/var/zookeeper
clientPort=2181
initLimit=5
syncLimit=2
server.1=myhdfs1:2888:3888
server.2=myhdfs2:2888:3888
server.3=myhdfs3:2888:3888


  • myidファイルの準備

前述のように zoo.cfg ファイルを修正して myhdfs1 にて ZooKeeper サーバを起動しようとしたところ、エラーが発生して怒られたのですが、どうも、conf/zoo.cfg の dataDir で指定した場所(/home/issei/tmp/zookeeper/)に、myidというファイルを用意する必要があるようです。
このmyidファイルには、server.XX にあたる数値を記述しておく必要があるみたいです。

myhdfs1> cat /home/issei/tmp/zookeeper/myid
1

今回、myhdfs2 は 2、myhdfs3 は 3 が記述された myid ファイルを用意しました。

myhdfs2> pwd
/home/issei/tmp/zookeeper
myhdfs2> cat myid
2
myhdfs2> pwd
/home/issei/tmp/zookeeper
myhdfs3> cat myid
3


  • 動作確認1(事前確認)

前回は myhdfs1 のみで ZooKeeper を起動したので、myhdfs1 の設定を、myhdfs2、myhdfs3 に反映して起動してみます。
一応、起動前の各サーバの jps の結果。

myhdfs1> jps
17497 NameNode
17753 SecondaryNameNode
17946 TaskTracker
17825 JobTracker
20445 Jps
17613 DataNode
myhdfs2> jps
32536 Jps
30593 DataNode
30698 TaskTracker
myhdfs3> jps
13488 Jps
11815 DataNode
11914 TaskTracker



  • 動作確認2(失敗編)

myhdfs1 で ZooKeeper サーバを起動するのですが、zkServer.sh start 時、myid ファイルが存在しないとエラーになります。

myhdfs1> ./bin/zkServer.sh start
JMX enabled by default
Using config: /home/issei/app/zookeeper-3.3.0/bin/../conf/zoo.cfg
Starting zookeeper ...
STARTED
[issei@myhdfs1 zookeeper]$ 2010-04-21 13:54:45,476 - INFO  [main:QuorumPeerConfig@90] - Reading configuration from: /home/issei/app/zookeeper-3.3.0/bin/../conf/zoo.cfg
2010-04-21 13:54:45,487 - INFO  [main:QuorumPeerConfig@287] - Defaulting to majority quorums
2010-04-21 13:54:45,491 - FATAL [main:QuorumPeerMain@83] - Invalid config, exiting abnormally
org.apache.zookeeper.server.quorum.QuorumPeerConfig$ConfigException: Error processing /home/issei/app/zookeeper-3.3.0/bin/../conf/zoo.cfg
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerConfig.java:110)
        at org.apache.zookeeper.server.quorum.QuorumPeerMain.initializeAndRun(QuorumPeerMain.java:99)
        at org.apache.zookeeper.server.quorum.QuorumPeerMain.main(QuorumPeerMain.java:76)
Caused by: java.lang.IllegalArgumentException: /home/issei/tmp/zookeeper/myid file is missing
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parseProperties(QuorumPeerConfig.java:297)
        at org.apache.zookeeper.server.quorum.QuorumPeerConfig.parse(QuorumPeerConfig.java:106)
        ... 2 more
Invalid config, exiting abnormally

ログをみると、/home/issei/tmp/zookeeper/myid file is missingと言われていることがわかります。
この場合、myid ファイルを用意してください。

  • 動作確認3(びっくりした編)

myid を用意して、myhdfs1 で ZooKeeper サーバを起動したところ、以下のようなログが定期的に・・・

2010-04-21 14:03:56,831 - INFO  [Thread-1:QuorumCnxManager$Listener@436] - My election bind port: 3888
2010-04-21 14:03:56,856 - INFO  [QuorumPeer:/0:0:0:0:0:0:0:0:2181:QuorumPeer@610] - LOOKING
2010-04-21 14:03:56,860 - INFO  [QuorumPeer:/0:0:0:0:0:0:0:0:2181:FastLeaderElection@649] - New election. My id =  1, Proposed zxid = 13
2010-04-21 14:03:56,871 - WARN  [WorkerSender Thread:QuorumCnxManager@361] - Cannot open channel to 2 at election address myhdfs2/172.29.11.112:3888
java.net.ConnectException: Connection refused
        at sun.nio.ch.Net.connect(Native Method)
        at sun.nio.ch.SocketChannelImpl.connect(SocketChannelImpl.java:507)
        at java.nio.channels.SocketChannel.open(SocketChannel.java:146)
        at org.apache.zookeeper.server.quorum.QuorumCnxManager.connectOne(QuorumCnxManager.java:347)
        at org.apache.zookeeper.server.quorum.QuorumCnxManager.toSend(QuorumCnxManager.java:320)
        at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.process(FastLeaderElection.java:353)
        at org.apache.zookeeper.server.quorum.FastLeaderElection$Messenger$WorkerSender.run(FastLeaderElection.java:326)
        at java.lang.Thread.run(Thread.java:619)
... 続く ...

よくよくみると、myhdfs2 へ接続しようとしている感じです。
※この時点で、myhdfs1 上でしか ZooKeeper を起動していない。

  • 動作確認4(気を取り直して編)

というわけで、myhdfs1/myhdfs2/myhdfs3 を連続で起動してみることにする。
myhdfs1 ⇒ myhdfs2 ⇒ myhdf3 の順番で、bin/zkServer.sh startを実行したところ、タイミングの違いで myhdfs1/myhdfs2 では前述の警告(WARN)が表示されましたが、最後に起動した myhdfs3 では警告は出ませんでした。


起動後の各サーバの jps の結果を以下に。

myhdfs1> jps
17497 NameNode
17753 SecondaryNameNode
17946 TaskTracker
20834 Jps
17825 JobTracker
17613 DataNode
20792 QuorumPeerMain

QuorumPeerMain というのが起動していることがわかります。

myhdfs2> jps
30593 DataNode
32754 Jps
32716 QuorumPeerMain
30698 TaskTracker

こちらも。

myhdfs3> jps
13679 Jps
11815 DataNode
11914 TaskTracker
13635 QuorumPeerMain

こちらも。


というわけで、見た目上は、ZooKeeper クラスタが起動したように思える。

  • 動作確認5(クライアントから接続してみる編)

で、クライアントから接続してみる。


まずは myhdfs1 から、サーバをローカルとして接続を試みる。
以下、接続してls /してquitするという単純な接続確認。

myhdfs1> cd ~/app/zookeeper
myhdfs1> ./bin/zkCli.sh -server myhdfs1
Connecting to myhdfs1
2010-04-21 14:16:34,111 - INFO  [main:Environment@97] - Client environment:zookeeper.version=3.3.0-925362, built on 03/19/2010 18:38 GMT
2010-04-21 14:16:34,117 - INFO  [main:Environment@97] - Client environment:host.name=xxx.yyy.zzz
2010-04-21 14:16:34,118 - INFO  [main:Environment@97] - Client environment:java.version=1.6.0_18
... ログ ...
2010-04-21 14:16:34,238 - INFO  [main-SendThread(myhdfs1:2181):ClientCnxn$SendThread@908] - Socket connection established to myhdfs1/172.29.11.201:2181, initiating session
2010-04-21 14:16:34,262 - INFO  [main-SendThread(myhdfs1:2181):ClientCnxn$SendThread@701] - Session establishment complete on server myhdfs1/172.29.11.111:2181, sessionid = 0x1281ec516d70001, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
[zk: myhdfs1(CONNECTED) 0] ls /
[zookeeper]
[zk: myhdfs1(CONNECTED) 1] quit
Quitting...
2010-04-21 14:16:53,440 - INFO  [main:ZooKeeper@538] - Session: 0x1281ec516d70001 closed
myhdfs1>

大丈夫のようです。


次に、myhdfs1 から myhdfs3 をサーバに指定してつないで見ます。

myhdfs1> ./bin/zkCli.sh -server myhdfs3
Connecting to myhdfs3
2010-04-21 14:19:58,475 - INFO  [main:Environment@97] - Client environment:zookeeper.version=3.3.0-925362, built on 03/19/2010 18:38 GMT
... ログ... 
[zk: myhdfs3(CONNECTING) 0] 2010-04-21 14:19:58,684 - INFO  [main-SendThread(myhdfs3:2181):ClientCnxn$SendThread@701] - Session establishment complete on server myhdfs3/172.29.11.113:2181, sessionid = 0x3281ec4fd4b0000, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null

[zk: myhdfs3(CONNECTED) 0] ls /
[zookeeper]
[zk: myhdfs3(CONNECTED) 1] quit
Quitting...
2010-04-21 14:20:03,936 - INFO  [main:ZooKeeper@538] - Session: 0x3281ec4fd4b0000 closed
myhdfs1>

大丈夫のようです。


念のため、myhdfs2 から myhdfs3 に接続し、create /zk_test my_dataをしてみます。

myhdfs2> ./bin/zkCli.sh -server myhdfs3
Connecting to myhdfs3
2010-04-21 14:21:36,015 - INFO  [main:Environment@97] - Client environment:zookeeper.version=3.3.0-925362, built on 03/19/2010 18:38 GMT
... ログ ...
Welcome to ZooKeeper!
2010-04-21 14:21:36,189 - INFO  [main-SendThread(myhdfs3:2181):ClientCnxn$SendThread@701] - Session establishment complete on server myhdfs3/172.29.11.112:2181, sessionid = 0x3281ec4fd4b0001, negotiated timeout = 30000

WATCHER::

WatchedEvent state:SyncConnected type:None path:null
JLine support is enabled
[zk: myhdfs3(CONNECTED) 0] ls /
[zookeeper]
[zk: myhdfs3(CONNECTED) 1] create /zk_test my_data
Created /zk_test
[zk: myhdfs3(CONNECTED) 2] ls /
[zookeeper, zk_test]
[zk: myhdfs3(CONNECTED) 3] get /zk_test
my_data
cZxid = 0x100000008
ctime = Wed Apr 21 14:22:07 JST 2010
mZxid = 0x100000008
mtime = Wed Apr 21 14:22:07 JST 2010
pZxid = 0x100000008
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0
[zk: myhdfs3(CONNECTED) 4] delete /zk_test
[zk: myhdfs3(CONNECTED) 5] ls /
[zookeeper]
[zk: myhdfs3(CONNECTED) 6] quit
Quitting...
2010-04-21 14:22:10,458 - INFO  [main:ZooKeeper@538] - Session: 0x3281ec4fd4b0001 closed
myhdfs2>

というわけで、一通り大丈夫のようです。

  • 動作確認6(こうするとどうなる?編)

クラスタということで、myhdfs1 に接続して /zk_test を作成し、別のクライアントから myhdfs3 に接続して /zk_test を参照してみます。
myhdfs2 から myhdfs1 に接続し、/zk_test を作成

[zk: myhdfs1(CONNECTED) 1] ls /
[zookeeper]
[zk: myhdfs1(CONNECTED) 2] create /zk_test my_data
Created /zk_test
[zk: myhdfs1(CONNECTED) 3] ls /
[zookeeper, zk_test]
[zk: myhdfs1(CONNECTED) 4] get /zk_test
my_data
cZxid = 0x10000000c
ctime = Wed Apr 21 14:32:38 JST 2010
mZxid = 0x10000000c
mtime = Wed Apr 21 14:32:38 JST 2010
pZxid = 0x10000000c
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0

この状態で、myhdfs1 から myhdfs3 に接続し、/zk_test を get してみると

[zk: myhdfs3(CONNECTED) 0] get /zk_test
my_data
cZxid = 0x10000000c
ctime = Wed Apr 21 14:32:38 JST 2010
mZxid = 0x10000000c
mtime = Wed Apr 21 14:32:38 JST 2010
pZxid = 0x10000000c
cversion = 0
dataVersion = 0
aclVersion = 0
ephemeralOwner = 0x0
dataLength = 7
numChildren = 0

とれますねー。ctime/mtime あたりが同じなので、同じなのでしょう。
というわけで、/zk_test を delete して動作確認は完了ということで。

  • 動作確認7(ステータス確認編)

マニュアルで、zoo.cfg のサーバ記述のところで、leaderを決めるとか書いてありましたが、zkServer.sh statusで確認できるようです。
コンソールにログがでるとやっぱりうっとうしいので、log4j.properties の rootLogger から CONSOLE を削除して再起動してみたときの例。


myhdfs2/myhdfs3 で zkServer.sh status を実行すると

myhdfs2> ./bin/zkServer.sh status
JMX enabled by default
Using config: /home/issei/app/zookeeper-3.3.0/bin/../conf/zoo.cfg
Mode: follower

という感じで、Mode: followerとなります。
このとき、myhdfs1 でステータスを確認すると

myhdfs1> ./bin/zkServer.sh status
JMX enabled by default
Using config: /home/issei/app/zookeeper-3.3.0/bin/../conf/zoo.cfg
Mode: leader

となりました(邪魔なコンソールログは削除)。
それで、myhdfs3/myhdfs2/myhdfs1 の順番で log4j.properties を書き換えて再起動したところ、myhdfs1 が leader ではなくなっていました。

myhdfs1> ./bin/zkServer.sh status
JMX enabled by default
Using config: /home/issei/app/zookeeper-3.3.0/bin/../conf/zoo.cfg
Mode: follower

調べてみたところ、myhdfs3 が leader になっていました。


というわけで、leader が落ちると、ちゃんと引き継いでくれるということがわかりました。とさ。


以上、長くなりましたが、これでまた HBase に戻れます。