分散Erlang・Elixirノード間の通信する際に使える便利なrpcというErlangモジュールがあります。ネット調べてもあまり情報が出てきません。忘れないうちにメモしておきます。
rpcはphoenix_live_dashboardで利用されています。
一般論としてのRPC
ウィキペディアによると、一般論としては
遠隔手続き呼出し(英: remote procedure call、リモートプロシージャコール、略してRPC)とは、プログラムから別のアドレス空間(通常、共有ネットワーク上の別のコンピュータ上)にあるサブルーチンや手続きを実行することを可能にする技術。
Erlangのrpcモジュール
ErlangのrpcモジュールはErlang・Elixirノード間限定で使用できるものであるようです。ですので、BEAM (Erlang virtual machine)が使えないシステムに対して遠隔手続き呼出ししたい場合は別途調査が必要と思われます。
ドキュメントの内容をざっくり要約すると
- 遠隔手続き呼出しに似た機能
- 遠隔ノードで情報を収集したり、 遠隔ノードで特定の副作用を伴う機能を実行したりするために使用される
- :rpc.call/4やそれに似た関数では、成功した結果、発生した例外、およびその他のエラーを区別することが非常に困難
- 互換性の理由により変更できないため、異なる結果を区別できるerpcモジュールがOTP 23から新しく導入された
ちなみにerl -man
コマンドをOSのシェルに打ち込んでドキュメントを閲覧することもできます。
erl -man rpc
論よりRun
- 二つのノードをそれぞれ別々のIExセッションで起動
- 二つのノードを接続
- :rpc.call/4関数を使い遠隔ノード内でコード実行
ノードを起動
IExセッションで起動時に以下のオプションを指定します。
-
--sname
オプションで一意のノード名を指定 -
--cookie
オプションに同じクッキー(クラスターの名前ようなもの)を指定
二つのノード(hoge
、fuga
)をそれぞれ別々のIExセッションで起動します。
iex --sname hoge@localhost --cookie mycookie
iex --sname fuga@localhost --cookie mycookie
ノードを接続
ここではhoge
ノードのIExからfuga
ノードに接続します。逆でも構いません。
:pong = Node.ping(:"fuga@localhost")
Node.ping/1は、接続に成功した場合は :pong
、失敗した場合は:pang
を返します。
新しいノードがクラスタに加わると、メッシュネットワークが形成されます。クラスタの全てのノードは他の全てのノードに接続されます。
Node.list/0で現在接続されているノードのリストが確認できます。
遠隔ノード内でコード実行
:rpc.call/4を用いて別ノード内でコードを実行します。Node.spawn/2と似ていますが、:rpc.call/4を使うと別ノード内で計算した結果を簡単に受信できます。
検証用に簡単な挨拶をする関数を定義します。この関数はノードを受け取り、挨拶の文字列を返します。
defmodule Person do
@spec say_hello(Node.t()) :: String.t()
def say_hello(other_node) do
"Hello, #{node_name_string(other_node)}! My name is #{node_name_string(Node.self())}."
end
defp node_name_string(other_node) do
node
|> to_string()
|> String.split("@")
|> hd()
|> String.capitalize()
end
end
hoge
ノードのIExからfuga
ノードに挨拶させます。
:rpc.call(:"fuga@localhost", Person, :say_hello, [node()])
fuga
ノードのIExからhoge
ノードに挨拶させます。
:rpc.call(:"hoge@localhost", Person, :say_hello, [node()])
この技を使うといろんな情報を遠隔ノードから収集することができます。
phoenix_live_dashboard
phoenix_live_dashboardではシステムの情報を収集する目的で:rpc.call/4が利用されています。
ご参考までに