この節ではLan内での分散プログラミングを行ないます。
基本的な扱いは前節の一つのホスト内での分散プログラミングと同等ですが、セキュリティの関係で
こちらのほうが多少難しいです。
Erlangの扱いに入る前に、環境について説明しておきます。
分散Erlangもホスト間で通信を行なうプログラムですので、ファイアーウォールなどの設定の影響を
受けます。設定方法はマシンごとにことなるので言及は避けますが、今回の実験ではLanと外部とを繋ぐルータに
ファイアーウォールの設定して、Lan内部のホストはファイアーウォールの設定を解除しています。
こうすることにより、Lan内の通信をファイアーウォールにより妨げられることを防げます。
なお、解除したファイアーウォールを開始させることを忘れないようにして下さい。
複数のホスト間で分散Erlangを行なうには、分散Erlangのグループに参加するという形態を取ります。 そのために必要なことは
ということです。
クッキーは任意のホストを分散Erlangに接続させるためのセキュリティの機能を担っています。
パスワードと似たような役割を持っていて、同一のクッキーの値が設定されたホスト間でのみ分散Erlangを行なうことが可能です。
cookieはホームディレクトリにある .erlang.cookie の値が静的に利用されますが、
Erlangランタイムシステムを起動する際のオプションや、ある関数を実行することにより動的に値を変更することが可能です。
動的に変更した値はシステムを終了した際に元の値(.erlang.cookieの値)に戻ります。
分散Erlangを開始してみます。
ada:~ yuichi$ erl -name luigi -setcookie abc
Erlang (BEAM) emulator version 5.6.2 [source] [smp:2] [async-threads:0] [kernel-poll:false]
Eshell V5.6.2 (abort with ^G)
(luigi@ada.local)1>
オプション -name と -setcookie が利用されています。それぞれ、
ノード名の指定とクッキーの値の指定という役割を持っています。
一つのホスト内での分散Erlangの場合は -sname というオプションを利用しましたが、
ホスト間での分散Erlangを利用する際には -name というオプションを利用します。
-setcookie は先述した通り、cookieの値を他のホストと統一するために利用しています。
今回は名前が luigi で、クッキーが abc です。
それでは、もう片方のマシンを起動してみます。
delphi:~ yuichi$ erl -name mario -setcookie abc
Erlang (BEAM) emulator version 5.6.2 [source] [smp:2] [async-threads:0] [kernel-poll:false]
Eshell V5.6.2 (abort with ^G)
(mario@delphi.local)1>
これで両者の設定が完了しました。
他のホストにあるノードを確認できたら、あとは単一ホスト内での分散Erlangと 同じです。前の節で取り扱ったように、別のノードにある関数を呼び出すには 以下の関数を使います。
rpc:call(node, module, function, arity)
実験に使うコードです。
-module(name_server).
-export([start/0, loop/0]).
-export([ add_address/2, resolve_address/1]).
-define(REG_NAME, name_server).
start() ->
register(?REG_NAME, spawn(?MODULE, loop, [])).
loop() ->
receive
{From, {add_address, Domain, Address}} ->
put(Domain, Address),
From ! {?REG_NAME, ok};
{From, {resolve_address, Domain}} ->
Address = get(Domain),
From ! {?REG_NAME, Address}
end,
loop().
rpc(Query) ->
?REG_NAME ! {self() , Query},
receive
{?REG_NAME, Reply} ->
Reply
end.
add_address(Domain, Address) ->
Query = {add_address, Domain, Address},
rpc(Query).
resolve_address(Domain) ->
Query = {resolve_address, Domain},
rpc(Query).
簡単なDNSサーバらしき役割を持っています。ドメイン名をIPアドレスに変換する機能が簡単に実装されています。
start/0でサーバを起動し、add_address/2でドメインとIPアドレスの組み合わせを登録します。
そして、resolve_address/1でドメイン名よりIPアドレスを得ます。
使用するノードをそれぞれ立ち上げます。
ada:~/erlang/dist yuichi$ erl -name luigi -setcookie abc
Eshell V5.6.2 (abort with ^G)
(luigi@ada.local)1>
delphi :~ yuichi$ erl -name mario -setcookie abc
Eshell V5.6.2 (abort with ^G)
(mario@delphi.local)1>
marioノードから、別ホストにあるluigiノードに name_server を作り、実際に利用してみます。
(mario@delphi.local)1> rpc:call(luigi@ada.local, name_server, start, []).
true
(mario@delphi.local)2> rpc:call(luigi@ada.local, name_server, add_address,
(mario@delphi.local)2> ['www.google.co.jp','216.239.37.104']).
ok
(mario@delphi.local)3> rpc:call(luigi@ada.local, name_server,
(mario@delphi.local)3> resolve_address, ['www.google.co.jp']).
'216.239.37.104'
別のノードにあるマシンが動作しているようです。
最後に、相手のホストにあるノードを確認しているかテストをしてみましょう。
関数 nodes() は分散Erlangに参加しているマシンをリスト形式で返します。
次のように表示されたら成功です。
(luigi@ada.local)1> nodes().
['mario@delphi.local']
なんらかの問題があり、相手のホストにあるノードを認知していない場合は、 次のようにリストの中にノード名が含まれていません。
(luigi@ada.local)1> nodes().
[]
ただ、DNS登録してない場合はユーザが別のホストを利用するまでは、 Erlangシステムが他のノードを認知していなく、 関数を利用するなどして関わり合いを持つと、ノードが認知されるようです。 (このあたりはまだ詳細に調べていないのでよく分かりません。)