2012年11月19日月曜日

Node.jsが面白い件② redisを使う

Node.jsが面白い件①の続きです。今回はredisの使い方について書いていきます。redisはオープンソースのインメモリKVSとして有名で、ディスクへの書き込みやトランザクション機能も提供する優れものです。クラスタに関してはまだ安定版が出ていませんが、単体ではとても簡単に利用できます。以下、Macでのインストール手順です。詳しくはredisのページを参照してください。
  1. redisのダウンロードページからダウンロードする。
  2. 展開したディレクトリに移動しmakeを実行する。
  3. 同ディレクトリでmake testを実行する。
node.js側では以下のようにライブラリredis、hiredisをインストールします。例えば作業ディレクトリをRedisSampleとすると、以下のようにします。
 > mkdir RedisSample
 > cd RedisSample
 > npm install hiredis redis

RedisSampleディレクトリにサンプルプログラムapp.jsを作成し、以下の内容を記述します。

//redisの読み込み。
var redis = require('redis')

try {
    // コネクションの作成。defaultで127.0.0.1:6379を使う。
    console.log("-- connection open.");
    var client = redis.createClient();

    // onメソッドによるerrorイベント時の処理。
    client.on("error", function(err) {
        console.log("Error:" + err);
    });

    // password認証。redis.confでrequirepassにredispassを設定。
    console.log("-- auth");
    client.auth("redispass");

    // 全てのkeyを削除。
    console.log("-- flushdb");
    client.flushdb();

    // 文字列のkey-valueとして値を格納。key:key1、value:val1
    client.set("key1", "val1");

    // 格納した値を取得。 key: key1
    client.get("key1", function(err, obj) {
        console.log("get key1: " + obj);
    });

    // リストの保持。key: lkey、value: lval1, lval2
    client.lpush("lkey1", "lval1");
    client.lpush("lkey1", "lval2");

    // 格納したリスト値を取得。key:lkey1
    client.lrange("lkey1", 0, -1, function(err, obj) {
        console.log("get list lkey1: " + obj);
    });

    // ハッシュの保持。key: hkey1、value: hfld1:hval1, hfld2:hval2
    client.hset("hkey1", "hfld1", "hval1");
    client.hset("hkey1", "hfld2", "hval2");

    // 格納したハッシュ値を取得。 key:hkey1
    client.hgetall("hkey1", function(err, obj) {
        console.log("get hash hkey1");
        console.log(obj);
    });


    // トランザクションその1。成功。
    multi = client.multi();
    multi.set("mkey1", "mval1");
    multi.set("mkey2", "mval2");
    multi.exec(function(err, obj) {
        client.get("mkey1", function(err, rep1){
            console.log("get mkey1: "+rep1);
        });
        client.get("mkey2", function(err, rep2) {
            console.log("get mkey2: "+rep2);
        });

        // トランザクションその2。watchの値が更新されて失敗。
        client.set("wkey1", "wval1");
        client.watch("wkey1");
        client.set("wkey1", "wval-upd");
        multi = client.multi();
        multi.set("mkey1", "mval3");
        multi.set("mkey2", "mval4");
        multi.exec(function(err, obj) {
            client.get("mkey1", function(err, rep1){
                console.log("get mkey1: "+rep1);
            });
            client.get("mkey2", function(err, rep2) {
                console.log("get mkey2: "+rep2);
                console.log("-- connection close.");
                client.quit();
            });
        });
    });
} catch(err) {
    console.err(util.inspect(err));
}

結果は以下のようになります。
 > -- connection open.
 > -- auth
 > -- flushdb
 > get key1: val1
 > get list lkey1: lval2,lval1
 > get hash hkey1
 > { hfld1: 'hval1', hfld2: 'hval2' }
 > get mkey1: mval1
 > get mkey2: mval2
 > get mkey1: mval1
 > get mkey2: mval2
 > -- connection close.

2行目で最初にインストールしたredisを読み込みます。6行目でコネクションを作成して、あとはredisのコマンドにならって処理を実行しています。redisはトランザクションをサポートしていますが、51行目のトランザクション①は成功し、63行目のトランザクション②は失敗します。これはwatchを使って楽観的ロックを実現しており、この例の場合はwkey1をwatchしており、watch実行後からexec実行前までにwkey1が変更されているとトランザクションが失敗するため、結果としてはmkey1、mkey2はmval1、mval2のままとなります。
この例の場合、トランザクション①の結果表示でコールバックを使っているので、コールバック内にトランザクション②の処理を記述しています。Node.jsではコールバック処理をよく使うので処理結果の順序を保持したい場合はこのように意識して記述するか、簡素化のためにstepなどのモジュールを使って処理を記述することができます。
redisはNode.jsでは今のところよく使われる組み合わせなのですが、ここで書いたように基本的な使い方はとても簡単です。軽いプロトタイプなら、Node.jsとredisだけですぐに作れてしまいそうですね。

0 件のコメント:

コメントを投稿