Skip to content

Instantly share code, notes, and snippets.

@fujimisakari
Last active April 18, 2017 15:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fujimisakari/22115a70bf43473bc8845f143e6b9043 to your computer and use it in GitHub Desktop.
Save fujimisakari/22115a70bf43473bc8845f143e6b9043 to your computer and use it in GitHub Desktop.

プログラミングErlang - 分散プログラミング

10章あたり

分散プログラム

分散プログラムとは、ネットワークを構成するコンピュータで動作するように設計されたプログラムのこと。
Erlangの分散プログラムは、信頼できる動作環境でどのErlangノードでも他のノードに対して
メッセージパッシングだけを使ってお互いの動作の調和をとることができる

分散プログラムで名前サーバを作る

Erlangノードを起動して遠隔Erlangノードで遠隔手続き呼び出して実行するため
以下の手順を順番に追いながら簡単な名前サーバを作る。

  • ステージ1:分散していない通常のErlang システムで名前サーバを書いてテストする。
  • ステージ2:1 つのマシンにある2 つのノードで名前サーバをテストする。
  • ステージ3:1 つのローカルエリアネットワークにある2 台の異なるマシンの2 つの異なるノードで名前サーバをテストする。
  • ステージ4:2 つの異なる国の2つの異なるドメインに属する2台の異なるマシンで名前サーバをテストする。

ステージ1: 単純な名前サーバ

・kvs.erl

-module(kvs).
-export([start/0, store/2, lookup/1]).

start() -> register(kvs, spawn(fun() -> loop() end)).

store(Key, Value) -> rpc({store, Key, Value}).

lookup(Key) -> rpc({lookup, Key}).

rpc(Q) ->
    kvs ! {self(), Q},
    receive
        {kvs, Reply} -> Reply
    end.

loop() ->
    receive
        {From, {store, Key, Value}} ->
            put(Key, {ok, Value}),
            From ! {kvs, true},
            loop();
        {From, {lookup, Key}} ->
            From ! {kvs, get(Key)},
            loop()
    end.

・Eshell

1> c(kvs).
{ok,kvs}
2> kvs:start().
true
3> kvs:store({location, joe}, "Stookholm").
true
4> kvs:store(weather, raining).
true
5> kvs:lookup(weather).
{ok,raining}
6> kvs:lookup({location, joe}).
{ok,"Stookholm"}
7> kvs:lookup({location, jane}).
undefined

ステージ2: クライアントとサーバが1つのホストの別のノードにある場合

ステージ1で作ったプログラムを2つのEshellで別々のErlangノードとして起動して確認する。
rpc:callはErlangの標準ライブラリモジュールで以前に書いたrpc関数でない。

・Eshell Server

$ erl -sname server
(server@fujimisakaris-MacBook-Air)1> kvs:start().
true

・Eshell Client

$ erl -sname client
(client@fujimisakaris-MacBook-Air)1> rpc:call('server@fujimisakaris-MacBook-Air',
(client@fujimisakaris-MacBook-Air)1>          kvs, store, [weather, fine]).
true
(client@fujimisakaris-MacBook-Air)2> rpc:call('server@fujimisakaris-MacBook-Air',
(client@fujimisakaris-MacBook-Air)2>          kvs, lookup, [weather]).
{ok,fine}

ステージ3: クライアントとサーバが1つのLANに接続された別のマシンにある場合

dockerにて検証環境を構築(同一LANに別マシンのErlangノードの用意)。

・Server Host

$ docker run -it -v /path/to/erlang_socket_dist:/usr/src/app --name server erlang:latest /bin/bash
root@3c550c1df592:/# cd /usr/src/app
root@3c550c1df592:/usr/src/app# erl -name server@172.17.0.2 -setcookie abc
Erlang/OTP 19 [erts-8.3.1] [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.3.1  (abort with ^G)
(server@172.17.0.2)1> kvs:start().
true

・Client Host

$ docker run -it -v /path/to/erlang_socket_dist:/usr/src/app --name client erlang:latest /bin/bash
root@351e440c3070:/# cd /usr/src/app
root@351e440c3070:/usr/src/app# erl -name client@172.17.0.3 -setcookie abc
Erlang/OTP 19 [erts-8.3.1] [source] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]

Eshell V8.3.1  (abort with ^G)
# pingで疎通確認
(client@172.17.0.3)1> net_adm:ping('server@172.17.0.2').
pong
(client@172.17.0.3)2> rpc:call('server@172.17.0.2',
(client@172.17.0.3)2>          kvs, store, [weather,cold]).
true
(client@172.17.0.3)3> rpc:call('server@172.17.0.2',
(client@172.17.0.3)3>          kvs, lookup, [weather]).
{ok,cold}

ステージ4:クライアントとサーバをインターネット上の別ホストで動作させる場合

検証環境がなかったので確認できずorz

クッキー保護システム

2つの分散Erlangノードが通信するには、双方が同じマジッククッキーを持っていなければならない。

クッキーは以下の3 種類の方法で設定できる

$HOME/.erlang.cookie というファイルに同じクッキーを入れておく

このファイルにはランダムな文字列が入っていて、
Erlangをそのマシンで初めて実行したときに自動的に作られる。
分散Erlang セッションに参加するすべてのマシンにこのファイルをコピーすればよい。
もしくは、値を明示的に設定することもできる。
例えば、Linux システムの場合、次のようなコマンドを実行する:

$ cd
$ cat > .erlang.cookie
AFRTY12ESS3412735ASDF12378
$ chmod 400 .erlang.cookie

Erlang を起動するときのコマンドライン引数に-setcookie C を指定する。

このフラグはマジッククッキーにC を設定する。

例えば:

$ erl -setcookie AFRTY12ESS3412735ASDF12378 ...

erlang:set_cookie(node(), C)を利用する

BIFのerlang:set_cookie(node(), C)を使って、ローカルノードのクッキーにアトムCを設定する。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment