riak_coreを使ってみる その1

riak はBasho社が作成している分散データベース です。実はRiakはriak_coreという分散処理を行う機能と、riakというデータベー ス機能(Riak K/V)とに分かれています。

そして、riak_coreは汎用的なフレームワークになっており、riakというデータ ベース以外の用途にも使えるようになっています。

今回は、途中までではありますが、触ってみたところを書きます。

riak_coreが提供する機能

http://www.slideshare.net/argv0/riak-coredevnation 参照

  • Virtual Node

  • Preference Lists

  • Ring Event Watcher

  • Node Event Watcher

参考文献

最初に読む場所

http://basho.com/where-to-start-with-riak-core/

サンプルアプリケーション

http://docs.basho.com/riak/1.4.0/references/appendices/community/Sample-Applications/

37ページからBuilding an Application on Riak Core

http://www.erlang-factory.com/upload/presentations/294/MasterlessDistributedComputingwithRiakCore-RKlophaus.pdf

riak_core 入門 by kuenishiせんせい

https://github.com/kuenishi/riak_scr_jp/blob/master/%234/ss-riak-core-intro.rst

riak_core モジュールドキュメント

http://basho.github.io/riak_core/

サンプルコード

try-try-try サンプルコード

https://github.com/rzezeski/try-try-try

howl

https://github.com/project-fifo/howl

古いものなのですが、そのまま通用するのがすごいところ。

作ってみる

riak_coreを使ったアプリケーションを作成するにはまず https://github.com/basho/rebar_riak_core を使ってテンプレートを作成します。 (rebarは事前に入れておいてください)

% git clone git://github.com/basho/rebar_riak_core.git
% mkdir -p ~/.rebar/templates
% cp rebar_riak_core/* ~/.rebar/templates
% mkdir <プロジェクト名>
% cd <プロジェクト名>
% rebar create template=riak_core appid=<プロジェクト名>

これでテンプレートの出来上がりです。以下のようなファイル構造が出来上が ります。src以下は重要なので中身も書いてみました。

今回は、プロジェクト名をdpingにしたので、そのつもりで読んでください。

apps/
Makefile
README.md
rebar
rebar.config
rel/
src/
├── dping_app.erl
├── dping.app.src
├── dping_console.erl
├── dping.erl
├── dping.hrl
├── dping_node_event_handler.erl
├── dping_ring_event_handler.erl
├── dping_sup.erl
├── dping_vnode.erl
└── dping_wm_ping.erl

そのあとは、以下のようにすれば動きます。

% make rel
% ./rel/dping/bin/dping console

14:13:42.486 [info] Waiting for application dping to start (0 seconds).
14:13:42.489 [info] Application dping started on node 'dping@127.0.0.1'
Eshell V5.9.1  (abort with ^G)
(dping@127.0.0.1)1> 14:13:42.588 [info] Wait complete for
application dping (0 seconds)

(dping@127.0.0.1)2> dping:ping().
{pong,959110449498405040071168171470060731649205731328}

consoleでdping:ping()を実行して、というのが出れば成功です。 q() で終わります。

これは単一ノードだけですが、devrelを使うと4つのノードを作ってくれます。

% make devrel
mkdir -p dev
rel/gen_dev dev1 rel/vars/dev_vars.config.src
rel/vars/dev1_vars.config
Generating dev1 - node='dping1@127.0.0.1' http=10018 handoff=10019
(cd rel && ../rebar generate target_dir=../dev/dev1
overlay_vars=vars/dev1_vars.config)
==> rel (generate)
mkdir -p dev
rel/gen_dev dev2 rel/vars/dev_vars.config.src
rel/vars/dev2_vars.config
Generating dev2 - node='dping2@127.0.0.1' http=10028 handoff=10029
(cd rel && ../rebar generate target_dir=../dev/dev2
overlay_vars=vars/dev2_vars.config)
==> rel (generate)
mkdir -p dev
rel/gen_dev dev3 rel/vars/dev_vars.config.src
rel/vars/dev3_vars.config
Generating dev3 - node='dping3@127.0.0.1' http=10038 handoff=10039
(cd rel && ../rebar generate target_dir=../dev/dev3
overlay_vars=vars/dev3_vars.config)
==> rel (generate)
mkdir -p dev
rel/gen_dev dev4 rel/vars/dev_vars.config.src
rel/vars/dev4_vars.config
Generating dev4 - node='dping4@127.0.0.1' http=10048 handoff=10049
(cd rel && ../rebar generate target_dir=../dev/dev4
overlay_vars=vars/dev4_vars.config)
==> rel (generate)

こうしておいて、

以下のようにしてstartとjoinをします。

shirou@rudi:~/Works/dping$ for d in dev/dev*; do $d/bin/dping start;
done
shirou@rudi:~/Works/dping$ dev/dev3/bin/dping-admin join dping1@127.0.0.1
Sent join request to dping1@127.0.0.1
shirou@rudi:~/Works/dping$ for d in dev/dev*; do $d/bin/dping stop;
done

書いてみる

rebarで作成された中のdping_vnode.erlをみてみると、こんな感じの行があります。 これらを埋めていけばいいわけですね。

%% Sample command: respond to a ping
handle_command(ping, _Sender, State) ->
    {reply, {pong, State#state.partition}, State};
handle_command(Message, _Sender, State) ->
    ?PRINT({unhandled_command, Message}),
    {noreply, State}.

handle_handoff_command(_Message, _Sender, State) ->
    {noreply, State}.

handoff_starting(_TargetNode, State) ->
    {true, State}.

handoff_cancelled(State) ->
    {ok, State}.

handoff_finished(_TargetNode, State) ->
    {ok, State}.

handle_handoff_data(_Data, State) ->
    {reply, ok, State}.

encode_handoff_item(_ObjectName, _ObjectValue) ->
    <<>>.

is_empty(State) ->
    {true, State}.

delete(State) ->
    {ok, State}.

handle_coverage(_Req, _KeySpaces, _Sender, State) ->
    {stop, not_implemented, State}.

handle_exit(_Pid, _Reason, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

nodeの追加/更新が起きた場合にnodeのリストを取る場合には dping_ring_event_handler.erl にこう書きます。

handle_event({ring_update, _Ring}, State) ->
    Members = riak_core_ring:active_members(_Ring),
    io:format("ring update ~p~n",[Members]),
    {ok, State}.

こうしておいて、joinすると、attachしておいた端末にこう表示されます。

(dping1@127.0.0.1)1> 14:40:46.977 [info] 'dping3@127.0.0.1' joined cluster with status 'valid'
ring update ['dping1@127.0.0.1','dping3@127.0.0.1']
ring update ['dping1@127.0.0.1','dping3@127.0.0.1']
ring update ['dping1@127.0.0.1','dping3@127.0.0.1']

出てきた疑問点

  1. なんでring updateが複数回呼ばれるの?

    joined cluster with ... と書かれている部分はgosip部分で、それはAPI としては呼べない、のかな?

  2. handoff_staringが何度も呼ばれる

    なのに、handof_finishedが呼ばれてない。

うーん。もう少し挙動を調べる必要がある様子。

まとめ

  • riak_coreという分散処理のフレームワークがある

  • rebarでテンプレートを作成できる

  • テンプレートで作成された関数を埋めていけばいい

まだまだ理解不足ですが、一旦ここまで。

続きます。次はコマンドの作成です。

Comments

comments powered by Disqus