So-net無料ブログ作成
2011年01月11日| 2011年01月13日 |- ブログトップ

インフラエンジニアのためのCassandra情報 ZooKeeperその2 [Cassandra]

ZooKeeperのプログラミングについては、以下のURLに簡単なチュートリアルが
あります。
http://hadoop.apache.org/zookeeper/docs/r3.1.1/zookeeperTutorial.html
今回は、ここに載っているサンプルを使って、カウンターを実現してみます。
ZooKeeperはznodeと呼ばれるツリー構造のデータ構造を持っています。znodeのそれぞれに
対応するオブジェクト(または値)を保存することができます。znodeには、登録、更新時に
一意のバージョン番号が付与されるので、これを使うことで、CAS操作が実現できそうです。
そこで、「/app1/counter」というznodeを作成して、これにカウンター用の数値を代入、参照
するようにします。
カウントアップ時には、CAS操作を行っているので、複数プロセスからの同時書込み時でも値
の一意性が保証されます。
チュートリアルを参考にして、まず「/app1]」の作成部分は、
this.root = root_name; ← 「/app1」
counter = counter_name;
// Create ZK node name
if (zk != null) {
        try {
                Stat s = zk.exists(root, false);
                if (s == null) {
                        zk.create(root, new byte[0], Ids.OPEN_ACL_UNSAFE,
                                        CreateMode.PERSISTENT);
                }

となり、「/counter」の部分は、
b.putInt(0);    ← 初期値として0を入れる。
value = b.array();
zk.create(znode, value, Ids.OPEN_ACL_UNSAFE,
                        CreateMode.PERSISTENT); ← znode = /app1/counter

となります。この段階で既に変数として使えるようになっているので、カウンターの
初期値として「0」を入れておきます。
そして、CAS操作を実現するには、バージョン番号を取得し、カウントアップ後に
バージョン番号と一緒にznodeを更新します。このとき他のプロセスが更新していたら
Exceptionが発生するので、はじめからやり直します。
コードは以下のようになります。
int value = 0;
int retry = 0;

do {
        try {
                Stat stat = zk.exists(znode, false); ←バージョン番号を含むメタデータを取得
                byte[] b = zk.getData(znode,false, stat); ←現在の値を取得
                ByteBuffer buffer = ByteBuffer.wrap(b);
                value = buffer.getInt();

                value++;  ←カウントアップ

                ByteBuffer b1 = ByteBuffer.allocate(6);
                b1.putInt(value);
                b = b1.array();
                zk.setData(znode, b, stat.getVersion()); ←バージョン番号と一緒に、更新した値をセット
                retry = 0;
        } catch ( KeeperException e) { ←バージョン番号が変わっている場合は、KeeperExceptionが発生する
                retry = 1; ←一からやり直し
        }
}while(retry > 0);

出来上がったカウンターのソース(CounterPrimitive.java)は
https://github.com/so-net-developer/Cassandra/blob/master/zookeeper/CounterPrimitive.java
にあります。
使用方法は、以下のとおり。
ZookeeperライブラリをCLASSPATHに指定します。
$ export CLASSPATH=./:/usr/lib/zookeeper-3.3.1/zookeeper-3.3.1.jar:/usr/lib/zookeeper-3.3.1/lib/log4j-1.2.15.jarog4j-1.2.15.jar

コンパイル
$ javac CounterPrimitive.java

使い方は、
カウンタの作成:
java CounterPrimitive [Zookeeperノードアドレス] n
カウンタのインクリメント
java CounterPrimitive [Zookeeperノードアドレス] i [増分]
カウンタの削除
java CounterPrimitive [Zookeeperノードアドレス] d

使用例)
$ java CounterPrimitive localhost n
Input: localhost
New Counter

$ java CounterPrimitive localhost i 10
Input: localhost
Item: 10

$ java CounterPrimitive localhost i 10
Input: localhost
Item: 20          <- カウントアップされている。

$ java CounterPrimitive localhost d
Input: localhost
Deleted

参考までに、rubyでのサンプルも
https://github.com/so-net-developer/Cassandra/blob/master/zookeeper/CounterPrimitive.rb
に載せておきます。rubyに馴染みのひとはこちらのほうが見やすいかも。

2011年01月11日| 2011年01月13日 |- ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。

×

この広告は1年以上新しい記事の更新がないブログに表示されております。