④Elixirエッジコンピューティング：Elixirエッジサーバのクラスタリング入門

この記事は、[Elixir Advent Calendar 2024 シリーズ3](https://qiita.com/advent-calendar/2024/elixir) の21日目です

昨日は、@RyoWakabayashi さんで [「Advent of code 2015 Day 10 Part 1 & Part 2 を Livebook で楽しむ」](https://qiita.com/RyoWakabayashi/items/3a7fc1927b741fca900a) でした

---

[piacere](https://twitter.com/piacere_ex) です、ご覧いただいてありがとございます :bow:

[前回](https://qiita.com/piacerex/items/401cbe7bb5898c3d8308) は、クラウドを使わずにリアルタイム性を担保するElixirならではの分散コンピューティングの基礎を示しました

今回は、その基礎を土台にモダンなクラスタリング機能群を備える [libcluster](https://github.com/bitwalker/libcluster) というライブラリを使って、Elixirにおける「クラスタリング」に入門していきます

https://github.com/bitwalker/libcluster

なお今回の内容は、libcluster無しでも実現できますが、次回以降に必要なオートスケールやダウン時自動復帰も簡単に実現したいため、今回からlibclusterを使っていきます

本シリーズの全体像は、下記になります

:::note warn
[①クラウドからエッジ／エッジサーバに拡がる未来とElixir](https://qiita.com/piacerex/items/ba0143f784cf360dda5f)
[②Elixiが叶えるエッジコンピューティングで最も重要なこと](https://qiita.com/piacerex/items/979cfa7575b880144c4c)
[③クラウドを使わないElixir分散コンピューティング](https://qiita.com/piacerex/items/401cbe7bb5898c3d8308)
[④Elixirエッジサーバのクラスタリング入門](https://qiita.com/piacerex/items/f49b9531f86d7aa02b2a)
[⑤Elixirエッジサーバのオートスケール／ダウン後自動復帰](https://qiita.com/piacerex/items/3a19a3a43f3d49bf3f63)
:::

### :xmas-tree: There are 13 Elixir Advent Calendar, making for a hot winter! :xmas-tree:

[Over the past 7 years, Elixir has consistently been a top-ranking language](https://speakerdeck.com/piacerex/7nian-jian-sok-ke-totupurankaru-risitaelixirniyoukoso?slide=13) in the programming category of the Advent Calendar, [claiming the #1 spot last year](https://qiita.com/advent-calendar/2023/ranking/feedbacks/categories/programming_languages). This year, too, Elixir is sure to stay at the top.

We’re feeling the excitement again this year… Please support or subscribe! :bow:

https://qiita.com/advent-calendar/2024/elixir
https://qiita.com/advent-calendar/2024/ranking/feedbacks/categories/programming_languages
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/74211dea-90bd-3de9-d700-24d25414aa05.png)](https://qiita.com/advent-calendar/2024/ranking/feedbacks/categories/programming_languages)

# Elixirクラスタリング入門

まず、1台目のマシンでPJを作成し、分散接続可能な起動をします

`--sup` を付けると、libclusterを使うために必要なスーパーバイザー設定が標準で入ります

```diff_elixir:【1台目のマシン】
mkdir apps
cd apps
mix new a --sup
cd a
```

次に、2台目のマシンでもPJを作成します

```diff_elixir:【2台目のマシン】
mkdir apps
cd apps
mix new b
cd b
```

ここで、1台目の方に、libclusterのインストールを行います

```diff_elixir:mix.exs【1台目のマシン】
defmodule A.MixProject do
  use Mix.Project
…
  # Run "mix help deps" to learn about dependencies.
  defp deps do
    [
      # {:dep_from_hexpm, "~> 0.3.0"},
      # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
+     {:libcluster, "~> 3.4"}
    ]
  end
…
```

「EPMD」というElixirノードの位置共有／解決を行うメカニズムをクラスター化の戦略として使います

このEPMDは、[前回行った `Node.connect` や `Node.list`](https://qiita.com/piacerex/items/979cfa7575b880144c4c#%E3%82%AF%E3%83%A9%E3%82%A6%E3%83%89%E3%82%92%E4%BD%BF%E3%82%8F%E3%81%9A%E3%81%AB%E5%88%86%E6%95%A3%E3%82%B3%E3%83%B3%E3%83%94%E3%83%A5%E3%83%BC%E3%83%86%E3%82%A3%E3%83%B3%E3%82%B0%E3%82%92%E5%8F%B6%E3%81%88%E3%82%8B) を支えるメカニズムでもあります

```diff_elixir:lib/a/application.ex【1台目のマシン】
defmodule A.Application do
  # See https://hexdocs.pm/elixir/Application.html
…
    def start(_type, _args) do
+   topologies = [
+     clusters1: [
+       strategy: Cluster.Strategy.Epmd,
+       config: [hosts: [:"node1@172.24.176.1", :"node2@172.24.176.2"]]
+     ]
+   ]
    children = [
      # Starts a worker by calling: A.Worker.start_link(arg)
      # {A.Worker, arg}
+     {Cluster.Supervisor, [topologies, [name: A.ClusterSupervisor]]}
    ]
…
```

これで1台目のマシンが、2台目のマシンを自動認識／接続し、クラスターを構成してくれるようになりました

なお、下記のように `config.ex` で設定することも可能です

https://github.com/bitwalker/libcluster?tab=readme-ov-file#example-configuration

では、クラスター化をするので、まず2台目のマシンを起動します

```:【2台目のマシン】
iex --name node2@172.24.176.2 --cookie edge-servers -S mix
```

その後、libclusterが動く1台目のマシンを起動します

```:【1台目のマシン】
mix deps.get
iex --name node1@172.24.176.1 --cookie edge-servers -S mix
```

その際、下記のようなメッセージが出れば、クラスター化に成功しています

```
[info] [libcluster:clusters1] connected to :"node1@172.24.176.1
```

ノードを見ると、自動接続していることが確認できます

```:【1台目のマシン】
iex> Node.list
[:"node1@172.24.176.1"]
```

なお、2台目のiexが起動していなかったり、ポートが閉じていたりすると、warningが出て、Node.listしても空のリストのままです

```
[warning] [libcluster:clusters1] unable to connect to :"node1@172.24.176.1"
```

3台以上のノードも、下記のように追記することで追加していけます

```diff_elixir:lib/a/application.ex【1台目のマシン】
defmodule A.Application do
  # See https://hexdocs.pm/elixir/Application.html
…
    def start(_type, _args) do
    topologies = [
      clusters1: [
        strategy: Cluster.Strategy.Epmd,
+       config: [hosts: [:"node1@172.24.176.1", :"node2@172.24.176.2", :"node3@172.24.176.3"]]
…
```

3台以上のノードがあると、下記のようになります

```:【1台目のマシン】
iex> Node.list
[:"node2@172.24.176.2", :"node3@172.24.176.3"]
```

# クラスターのノード間アクセスの確認

さて、クラスター内の別ノードにアクセスしてみましょう

2台目のマシンのiexのプロセスIDを取得します

```:【2台目のマシン】
iex> self
#PID<0.138.0>
```

1台目のマシンから、この2台目のマシンのiexプロセス情報を取得できれば、クラスター化された別ノードへのアクセスが可能であることになります

```diff_elixir:【1台目のマシン】
iex> :erlang.list_to_pid('<0.138.0>') |> Process.info
[
  registered_name: :ssl_connection_sup,
  current_function: {:gen_server, :loop, 7},
  initial_call: {:proc_lib, :init_p, 5},
  status: :waiting,
  message_queue_len: 0,
  links: [#PID<0.139.0>, #PID<0.146.0>, #PID<0.133.0>],
  dictionary: [
    "$initial_call": {:supervisor, :ssl_connection_sup, 1},
    "$ancestors": [:ssl_sup, #PID<0.129.0>]
  ],
…
```

1台目のマシン上で2台目のマシンのiexプロセス情報が取得できました

# ここまでで何が可能となったのか？

複数Elixirノードを1つのクラスターとして扱えるようになったことで、下記のようなことが可能となっています

- 複数ノードでクラスターを組める
- [前回実施した `nl()` のでノード複製ができる](https://qiita.com/piacerex/items/979cfa7575b880144c4c#%E3%83%8E%E3%83%BC%E3%83%89%E9%96%93%E3%81%AE%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E8%A4%87%E8%A3%BD)

これらにより、クラウドを使わずともクラスタリングが実現できるので、複数ノードで構成されるエッジサーバを簡単に実現できます

ただし、デフォルトのEPMD戦略だけでは、下記のようなモダンなクラスタリング制御は残念ながら出来ません

- クラスターをオートスケールできない
- ノードダウン後のアップ時にクラスターに自動復帰できない


これは、libclusterの限界では無く、あくまでEPMD戦略の限界なため、他の戦略を使う以降のコラムで解決していきます

# 終わりに

Elixirのクラスタリングが、思った以上に簡単に構築できることが共有できたら幸いです

一方で、現段階では実用的なクラスタリングのようにも見えないため、[次回はそこを解決すべく、モダンなクラスタリング制御であるオートスケール／ダウン後自動復帰を実現](https://qiita.com/piacerex/items/3a19a3a43f3d49bf3f63) してきます

# p.s.このコラムが、面白かったり、役に立ったら…

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/907a8695-4d83-1b5c-8052-d0ce52de5f66.png) にて、どうぞ応援よろしくお願いします :bow:

---

明日は、 @mokichi さんで 「Stripeで従量課金を実現する」 です