ZooKeeper を使ってみる(1)
Hadoopのサブプロジェクトの一つにZooKeeperというのがある。分散システムを作るためのビルディングブロックとして非常に重要になってきそうなので、ちょっと調べて見ようと思う。ストリームコンピューティングシステムのS4でも使われているそうだ。どう使われているのかは知らない。
ZooKeeperとは
ZooKeeperは、GoogleのChubbyを模したシステム。HadoopがGoogleのGFSとMapReduceを模したのと同じ構図だ。
じゃあ、Chubbyはなんなのか、というとこれも一言で説明するのは難しい。非常に小規模なファイルに特化した分散ファイルシステム、ということになるのだろうが、実にさまざまな目的に使われているらしい。DNS代わり、ロックサービス、サービスの死活判定などなど。ZooKeeperは一通りこれらの目的に使えるようにできているようだが、どのくらい機能的に忠実なコピーになっているのかは、Googleの中の人にしかわからない。
Chubby は耐障害性のためにPaxosを用いた複製を採っていることでも知られている。5つのサーバで「セル」を構成し、そのうちの3台が生きていれば正常に処理が続行できる。ZooKeeperも同じ構造を持つ。
チュートリアルにはZooKeeperを使って複数のプロセス間のバリア同期や、プロセス間での生産者消費者キューの作り方が載ってる。AmazonのSQSみたいなものは簡単に作れるのかも知れない。
スタンドアローンモードと、CLIクライアント
まずは、スタンドアロンモードで動かしてみる。1台のみで動かすモードだ。複製はとられないので、耐障害性はないが、アプリケーションの開発にはお手軽だ。
まずコンフィグファイルをつくる。
tickTime=2000 dataDir=/tmp/zookeeper clientPort=2181
conf/zoo.cfg という名前にしておくとbin/zkServer.sh がそのまま使えて便利。2181はデフォルトのport。もちろん
> mkdir /tmp/zookeeper
としておくこと。
> bin/zkServer.sh start
とするとざらざらログが出て起動する。
ここで、CLIのクライアントを起動する。
> bin/zkCli.sh
デフォルトでローカルホストの2181に接続に行くので引数は不要。接続に成功すると、プロンプトが出る。
ここで helpと打つとコマンド一覧が出る。基本的には階層的な名前空間に値を置いていくということなので、操作はシェルに似ている。
ls。最初は何も入っていない。
[zk: localhost:2181(CONNECTED) 2] ls / [zookeeper]
/tmp というパスを作り値を「content」と設定。ls してできていることを確認。
[zk: localhost:2181(CONNECTED) 3] create /tmp content Created /tmp [zk: localhost:2181(CONNECTED) 4] ls / [tmp, zookeeper]
/tmpをget。値だけでなく作成日時やACLなども表示されている。
[zk: localhost:2181(CONNECTED) 5] get /tmp content cZxid = 0x7 ctime = Thu Mar 03 01:28:17 JST 2011 mZxid = 0x7 mtime = Thu Mar 03 01:28:17 JST 2011 pZxid = 0x7 cversion = 0 dataVersion = 0 aclVersion = 0 ephemeralOwner = 0x0 dataLength = 7 numChildren = 0
Java でノードを作ってみる。
Javaから使ってみよう。指定されたノード、値を作成するプログラム。ZooKeeperクラスのcreateメソッドを使う。ACLの設定がちょっとめんどうだが、基本的にはストレートフォワードだ。
import java.util.ArrayList; import java.util.List; import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.KeeperException; import org.apache.zookeeper.ZooKeeper; import org.apache.zookeeper.data.ACL; import static org.apache.zookeeper.ZooDefs.Ids.*; import static org.apache.zookeeper.ZooDefs.Perms.*; public class AddNode{ public void run() throws KeeperException, InterruptedException { } public static void main(String[] args) throws Exception{ if (args.length != 3) { System.err .println("USAGE: AddNode hostPort znode val"); System.exit(2); } ZooKeeper zk = new ZooKeeper(args[0], 3000, null); List<ACL> acls = new ArrayList<ACL>(); acls.add(new ACL(ALL, ANYONE_ID_UNSAFE)); zk.create(args[1], args[2].getBytes(), acls, CreateMode.PERSISTENT); } }
java addNode localhost:2181 /tmp/tmp3 hoge
とかやる。
ちなみにこちらのプログラムは終了しない。ZooKeeper とのコネクションにスレッドが張り付いているのだろう。