LoginSignup
21
21

More than 5 years have passed since last update.

Riakを取り巻くErlangの世界

Last updated at Posted at 2013-12-06

このAdvent Calendarで度々話題になって(して)いる、Riak Source Code Reading。
Erlang/OTPを全く知らない人にとっては、Erlangの文法はもちろん、ファイルやディレクトリ構成など未知のことだらけだと思う。
「Erlang/OTP何それ美味しいの」状態から脱却し、Riakのコードを楽しく読むために必要な知識を書いていこう。

用語について

RiakはErlang/OTPで作成されている。
Erlangとは、エリクソン社が開発したプログラミング言語。
OTPとは、システムを作るフレームワークみたいなものだ。
RubyとRuby on Railsの関係を想像する人もいるかもしれないが、Erlang/OTPはそれより相互が依存している。
故に、正式にはErlang/OTPみたいに”ひとつ”として呼ばれることが多い。

そのOTPとは何なのか。
正式にはOpen Telecom Platformという名前。
飛行機本には、"大規模、耐障害、分散といった特徴を持つアプリケーションを作るためのライブラリや手続きの集合体"との解説がある。
なんのことだかよくわからないが、結局のところ、必要とされる名前の関数を、中身空っぽでもいいので書いていくと、いつの間にかエラーレポートやホットコードスワッピングなど高度な機能を持ったアプリケーションが作れるという便利システム、といったところか。
Riakの可用性、耐障害性を実現するのに、このOTPは多大な貢献をしている。

で、Erlangにはgemのようなものは無い。
CEANっていうPerlで言うCPANのErlang版があるっちゃあるんだけど、活発な更新はされていないようだ。
そこで、Bashoが作っているrebarというOSSだ。
rebarは、githubなどにホストされている有用なライブラリの依存関係やErlang VMの設定などを管理し、バイナリのリリースを行うまで面倒を見てくれる。
もちろんRiakや関連プロジェクトでも使われている。

とりあえずErlangアプリケーションを作ってみる

ただ説明を読むより、手を動かして小さなアプリケーションを作ってみたほうが良い。
まずはrebarについての理解を深めるため、小さなErlangアプリケーションを作ってみよう。
安心してほしい。設定ファイルを除き、Erlangは一行も書かない。
流れを大雑把に書くと、

  1. rebarをpullして使えるようにする
  2. rebarをアプリケーションルートにコピー
  3. myappという名前のアプリケーションを作成
  4. rebar.configを作成し、relディレクトリが見れるようにする
  5. relディレクトリを作成し、その中でmynodeという名前のノードを作成
  6. reltool.configを修正
  7. バイナリを生成

となる。
では、やってみよう。

1. rebarをpullして使えるようにする
[mymac@localhost devel]$ git clone https://github.com/basho/rebar.git
[mymac@localhost devel]$ cd rebar
[mymac@localhost rebar]$ ./bootstrap

2. rebarをアプリケーションルートにコピー
[mymac@localhost rebar]$  cd ..
[mymac@localhost devel]$ mkdir myriak
[mymac@localhost devel]$ cp rebar/rebar myriak

3. myappという名前のアプリケーションを作成
[mymac@localhost myriak]$ cd myriak
[mymac@localhost myriak]$ ./rebar create-app appid=myapp
==> myriak (create-app)
Writing src/myapp.app.src
Writing src/myapp_app.erl
Writing src/myapp_sup.erl

4. rebar.configを作成し、relディレクトリが見れるようにする
[mymac@localhost myriak]$ echo '{sub_dirs, ["rel"]}.' > rebar.config

5. relディレクトリを作成し、その中でmynodeという名前のノードを作成
[mymac@localhost myriak]$ mkdir rel
[mymac@localhost myriak]$ cd rel
[mymac@localhost rel]$ ls
[mymac@localhost rel]$ ../rebar create-node nodeid=mynode
==> rel (create-node)
Writing reltool.config
Writing files/erl
Writing files/nodetool
Writing files/mynode
Writing files/sys.config
Writing files/vm.args
Writing files/mynode.cmd
Writing files/start_erl.cmd
Writing files/install_upgrade.escript

6. reltool.configを修正
[mymac@localhost rel]$ mv reltool.config reltool.config.org
[mymac@localhost rel]$ sed -e 's/{incl_cond, include}/{incl_cond, include}, {lib_dir, ".."}/' reltool.config.org > reltool.config

7. バイナリを生成
[mymac@localhost rel]$ ../rebar generate
==> rel (generate)

では、Erlangを一行も書かずに生成したバイナリを使ってみよう。

[mymac@localhost rel]$ mynode/bin/mynode
Usage: mynode {start|start_boot <file>|foreground|stop|restart|reboot|ping|console|getpid|console_clean|console_boot <file>|attach|remote_console|upgrade}
[mymac@localhost rel]$ mynode/bin/mynode start
[mymac@localhost rel]$ mynode/bin/mynode ping
pong
[mymac@localhost rel]$ mynode/bin/mynode stop
ok

すばらしい!rebarすばらしい!
もちろんこれだけだと何の機能も持っていないので、アプリケーションを作る場合はこの状態をベースに独自のコードを追加していくことになる。
そのコードも、OTPの設計原則に則って書くことで、高度で実用的な機能を簡単に実現できるのだ。

OTPについてちょこっとだけ

以下のコードを見てほしい。

myapp_server.erl
-module(myapp_server).

-behavior(gen_server).

-export([start/0, stop/0]).
-export([init/1, handle_call/3,handle_cast/2, handle_info/2, terminate/2, code_change/3]).

start() ->
    gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).

stop() ->
    gen_server:call(?MODULE, stop).

init([]) ->
    {ok, Riakc} = riakc_pb_socket:start_link("127.0.0.1", 8087),
    {ok, Riakc}.

handle_call(_Request, _From, State) ->
    {reply, Reply, State}.

handle_cast(_Msg, State) ->
    {noreply, State}.

handle_info(_Info, State) ->
    {noreply, State}.

terminate(_Reason, _State) ->
    ok.

code_change(_OldVsn, State, _Extra) ->
    {ok, State}.

OTPを活用するアプリケーションを書く場合、所定の関数を実装する必要がある。
behaviorと書かれた部分でOTPアプリケーションの種類を指定する。
これは代表的なbehavior、gen_serverだ。
この例では、init関数のみ独自のコードを書きかけている。(本当は格好いいアプリケーションを書き上げて今日のカレンダーでドヤ顔したかった...)
もし必要な関数が実装されていなければ、コンパイラはここを見てエラーを出力する。

関数名(引数) ->
    なんか処理,
    なんか処理,
    ok.

みたいになっているだろう。
この関数名についてだが、引数の数が異なる関数は、名前が同じでも異なる関数として扱われる。
exportの部分でpublicにする関数を、関数名/引数の数 で指定している。
引数の数はarityと呼ばれ、Erlangでは重要なものなので注意してほしい。
最後に評価された値が返るので、この関数を呼ぶとokアトムが返ることになる。

まとめ

もはやRiak関係なくね...?

acknowledgements

この記事の内容のほぼ全てを@itawasaさんに教えてもらいました。
また、gen_serverとgen_fsmを中心に、behaviorに対する僕の誤解を解いてくれたのもitawasaさんです。
ありがとうございます。

21
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21