2008/03/18

Erlang: Mnesiaで分散DB

Erlangには標準でMnesiaというハッシュ型のデータベースが附属していて、SQLは 使えないものの、言語環境をインストールしておくだけで、高負荷環境ではボトル ネックになりがちなデータベース層が分散できるのが魅力的。
# erl
Erlang (BEAM) emulator version 5.6.1

Eshell V5.6.1  (abort with ^G)
% Node名の設定
1> net_kernel:start(['erl@host1.foo.com',longnames]).
{ok,<0.35.0>}
% 別のネットワークからの接続を受けつける為に共通のフレーズ設定
(erl@host1.foo.com)2> erlang:set_cookie(node(),'cookie').
true
もう一個のマシンでも立ち上げる。こっちは起動時にパラメータ設定をしてしまう。
# erl -name host2.bar.com -setcookie cookie
Erlang (BEAM) emulator version 5.6.1

Eshell V5.6.1  (abort with ^G)
(erl@host2.bar.com)1> 
host1よりデータベースの準備やテーブルを作成する。
%host1,host2に対してデータベースディレクトリの初期化(PostgreSQLのinitdbみたいなもの)
(erl@host1.foo.com)3> mnesia:create_schema(['erl@host1.foo.com','erl@host2.bar.com']).
ok
% host1でmnesiaのサービスをスタート
(erl@host1.foo.com)4> mnesia:start().
ok
% host2にmnesiaのサービスをスタートさせるようにRPC経由で実行
(erl@host1.foo.com)5> rpc:call('erl@host2.bar.com',mnesia,start,[]).
ok
% id,name,ageのフィールドだけある簡単なテーブルを定義して作成。(create table)
(erl@host1.foo.com)6> rd(user,{id,name,age}).
user
(erl@host1.foo.com)7> mnesia:create_table(user,[
  {disc_copies,['erl@host1.foo.com','erl@host2.bar.com']},
  {attributes,record_info(user)}
 ]).
{atomic,ok}
できた~。これでもう分散DBできてる、らしい。素晴しい。
% host1でデータを入れてみる(insert)
(erl@host1.foo.com)8> mnesia:transaction(
  fun()->
    mnesia:write(#user{id=1,name="junji",age=32}),
    mnesia:write(#user{id=2,name="koki",age=7})
    end
 ).
{atomic,ok}
% host2で閲覧してみる(select)
(erl@host2.bar.com)2> mnesia:transaction(
  fun()->mnesia:foldl(
    fun(User,Acc)->io:format("~p\n",[User])end,[],user)
  end
 ).
{user,2,"koki",7}
{user,1,"junji",32}
{atomic,ok}
% host2でデータを更新(update)
(erl@host2.bar.com)3> mnesia:transaction(
  fun()->[E]=mnesia:read(user,1,write),
         N=E#user{age=33},
         mnesia:write(N)
  end
 ).
{atomic,ok}
% host2で削除(delete)
(erl@host2.bar.com)4> mnesia:transaction(
  fun()->mnesia:delete({user,2})end
 ).
{atomic,ok}
% host1で閲覧(select)
(erl@host1.foo.com)9> mnesia:transaction(
  fun()->
    lists:foreach(
      fun(X)->
        io:format("~p\n",[mnesia:read(user,X,read)])
      end,
    mnesia:all_keys(user))
  end
 ).
[{user,1,"junji",33}]
{atomic,ok}
ここにもう一台サーバを追加してみようと思う。
% DBのディレクトリも起動時に指定
# erl -name host3.hoge.com -setcookie cookie -mnesia dir "'/var/mnesia'"
Erlang (BEAM) emulator version 5.6.1

Eshell V5.6.1  (abort with ^G)
% 事前にスキーマをつくらなくてよし
(erl@host3.hoge.com)1> mnesia:start().
ok
% 分散元のサーバを指定
(erl@host3.hoge.com)2> mnesia:change_config(extra_db_nodes,['erl@host1.foo.com']).
{ok,['erl@host1.foo.com']}
こんだけ。素晴しい。
% host3で閲覧(select)
(erl@host3.hoge.com)3> rd(user,{id,name,age}).
user
(erl@host3.hoge.com)4> mnesia:transaction(
  fun()->
    mnesia:select(user,[{#user{name='$1',_='_'},[],['$1']}],1,read)
  end
 ).
{atomic,{["junji"],
         {mnesia_select,user,
                        {tid,6,<0.37.0>},
                        'host3.hoge.com',disc_copies,
                        '$end_of_table',[],undefined,undefined,
                        [{#user{id = '_',name = '$1',age = '_'},[],['$1']}]}}}
ちなみに、Windowsではノード(Node)の指定に erl@host1.foo.com でシングルクォートしなくてもよかったのにLinuxでは
* 1: illegal expression
とか出てしまうので、最初すごく手間取った。

0 コメント: