この記事は、Elixir Advent Calendar 2024 シリーズ3 の21日目です
昨日は、@RyoWakabayashi さんで 「KinoLink で Livebook に OGP 対応のリッチなリンクを表示する」 でした
piacere です、ご覧いただいてありがとございます
前回 は、エッジコンピューティングで最も重要なのは「リアルタイム性」であり、それを阻害するのは一般的なWeb/AI開発の「常識」や「当たり前」であるクラウドにある点を言及した後、クラウド無しでも分散コンピューティングを叶えるElixirのイディオムを紹介しました
今回は、クラウドを使わずにリアルタイム性を担保するために、複数台のエッジサーバをElixirノード群で構成する基礎について解説します
本シリーズの全体像は、下記になります
There are 13 Elixir Advent Calendar, making for a hot winter!
Over the past 7 years, Elixir has consistently been a top-ranking language in the programming category of the Advent Calendar, claiming the #1 spot last year. This year, too, Elixir is sure to stay at the top.
We’re feeling the excitement again this year… Please support or subscribe!
https://qiita.com/advent-calendar/2024/elixir
https://qiita.com/advent-calendar/2024/ranking/feedbacks/categories/programming_languages
複数ノードを接続する
「① クラウドで処理すると損なわれる」を加味してクラウド利用を避けつつ、「② とは言え、クラウド相当が無ければ担保が大変」の「分散コンピューティング」を叶えるという「いいとこどり」をElixirは割とカンタンに叶えられます
まず、1台目のマシンでPJを作成し、分散接続可能な起動をします
ここで、--cookie edge-servers
に設定されているのは、同じ分散ノードに属することを示す名前で分散接続可能にしています
mkdir apps
cd apps
mix new a
cd a
iex --name node1@172.24.176.1 --cookie edge-servers -S mix
次に、2台目のマシンでもPJを作成し、やはり分散接続可能な起動をします
mkdir apps
cd apps
mix new b
cd b
iex --name node2@172.24.176.2 --cookie edge-servers -S mix
2台目のマシンから、1台目のマシンに接続し、接続ノードリストを見ると、1台目のマシンが見れます
ただし、ポート番号4369をファイアウォール等で閉じていると使えないので、あらかじめ空けておいてください
iex> Node.connect(:"node1@172.24.176.1")
iex> Node.list
[:"node1@172.24.176.1"]
1台目のマシンからも2台目のマシンが見れます
iex> Node.list
[:"node2@172.24.176.2"]
ノード間でプロセスを連携させる
2台が接続した状態で、プロセス連携をしてみましょう
1台目のマシンから2台目のマシンのiexにメッセージを送るために、まず2台目のマシンのiexにプロセス名を付けます
iex> :global.register_name(:iex2, self)
:yes
1台目のマシンから、この2台目のマシンのiexプロセスにメッセージを送るには、send
を使います
iex> send(:global.whereis_name(:iex2), "hello")
"hello"
2台目のマシンのiexプロセスにて receive
で受信し、受信したメッセージを表示しました
iex> receive do
...> message -> message
...> end
"hello"
1台目のマシンから、2台目のマシン上のモジュールを呼び出すことも出来ます
iex> send(:global.whereis_name(:iex2), &B.hello/0)
"hello"
2台目のマシン上にしか無いモジュールの関数を呼び出しました
iex> receive do
...> func -> func.()
...> end
:world
このように、ノード間を跨いだプロセス連携による分散処理が可能です
ノード間でモジュールを複製する
先ほどは、1台目のマシンから2台目のマシン上の関数を呼びましたが、今度は1台目のマシンに定義したコードを、2台目のマシンでも利用可能にしてみます
defmodule A do
def func(count) do
for i <- 1..count, do: i
end
end
まず、1台目のマシン上で、これを実行してみます
iex> A.func(5)
[1, 2, 3, 4, 5]
この段階では、2台目のマシン上にこの定義が無いため、エラーになります
iex> A.func(5)
** (UndefinedFunctionError) function A.func/1 is undefined (module A is not available)
A.func(5)
iex:4: (file)
ここで、1台目のマシンにあるコードを、下記コードで2台目に複製できます
iex> nl(A)
{:ok, [{:"node2@172.24.176.2", :loaded, A}]}
これで、2台目のマシン上でも実行できるようになります
iex> A.func(5)
[1, 2, 3, 4, 5]
3台以上の接続がある場合でも、同様に複製できます
iex> nl(A)
{:ok,
[{:"node2@172.24.176.2", :loaded, A}, {:"node3@172.24.176.3", :loaded, A}]
このようにElixirは、クラウドやコンテナを使うこと無く、分散コンピューティングをいとも容易く叶えます
終わりに
今回は、エッジコンピューティングのリアルタイム性担保のために、最も重要な「クラウド無しでの分散コンピューティング」をElixirのみで叶えました
しかも、サードパーティのライブラリやFWも特に導入しておらず、デフォルト状態のElixirのみで実現できています
この土台を中心に、上記②のマルチマスタかつ冗長化された分散DBの実現や、「⑥ 耐障害性が高くないとMTBF/MTTRが悪化して損なわれる」で述べた耐障害性とコンピュートエンジンの冗長化など、エッジコンピューティングに求められる「リアルタイム性」を叶える様々な事柄が、やはりカンタンに実現できます
次回は、クラウド無しでの分散コンピューティングの基本要素である「クラスタリング」を構築 していきます
p.s.このコラムが、面白かったり、役に立ったら…
明日は、 @RyoWakabayashi さんで 「Advent of code 2015 Day 11 Part 1 & Part 2 を Livebook で楽しむ」 です