Elixirプロセス間通信／分散／並行は20種類もあるってご存じでした？

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

---

【本コラムは、15分で読めます】　※各配下コラムをお読みいただく場合は各自次第で

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

Elixirプロセス間通信／分散／並行の方式は20種類もあるってご存じでした？

今年は、Elixirによるマイクロサービス／エッジコンピューティングの土台となる機能（Umbrella、Node、Livebookなど）とその優位性を、LT／スライド／コラム等で解説しましたが、来年はElixirプロセス間通信／分散／並行の20種類ある方式それぞれを活用した実践例を示していこうと思っており、本コラムはその前触れやカンタンな紹介です

なお、下記の皆さまのコラム／動画などをリンクさせていただきました（ありがとございます） :information_desk_person:

@kikuyuta さん
@twinbee さん
@32hero さん
@pojiro さん
@RyoWakabayashi さん 
@koyo-miyamura さん
@mokichi さん
@mnishiguchi さん

あと、このコラムが、面白かったり、役に立ったら、![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/907a8695-4d83-1b5c-8052-d0ce52de5f66.png) をお願いします :bow:

# ① Stream

遅延リスト処理を実行する [Streamモジュール](https://hexdocs.pm/elixir/Stream.html) は、プロセス単位の分離／分散では無いものの、並行処理の最もシンプルな例です

from @kikuyuta さん

https://qiita.com/kikuyuta/items/b6c74f3cb677aac4406e

# ② spawn／send／receive

spawnシリーズ（[関数を定義しつつプロセスとして起動](https://hexdocs.pm/elixir/Kernel.html#spawn/1)、[名前付き関数をプロセスとして起動](https://hexdocs.pm/elixir/Kernel.html#spawn/3)、[親プロセスとリンクするプロセスを起動](https://hexdocs.pm/elixir/Kernel.html#spawn_link/1) など）によるプロセス起動と、プロセス間でメッセージパッシングするsend／receiveは、並行／分散の最小単位です

from @piacerex

https://qiita.com/piacerex/items/96398166f72fc2d921e9

# ③ Parallel Map

リストの各要素に対し、上記したspawnシリーズで処理を行い、それをreceiveで受け取るようにしたものがParallel Mapです

同期並行処理を叶えます

from @RyoWakabayashi さん

https://qiita.com/RyoWakabayashi/items/ef858baebecf84028a14

# ④ Task

上記spawnをワーカープロセス化に特化したものが [Task](https://hexdocs.pm/elixir/Task.html) です

spawn／send／receiveのイディオムを、async／awaitによるシンプルな同期並行処理／ワーカープロセス化に置き換えます

from @pojiro さん

https://qiita.com/pojiro/items/050da725dde4d05fed9e

# ⑤ GenServer

上記Taskのようなワーカープロセスに加え、状態を保持できるようにサーバープロセス化したものが [GenServer](https://hexdocs.pm/elixir/GenServer.html) です　※正確には、GenSeverから状態保持をオミットして作られたものがTaskです

同期処理（[handle_call](https://hexdocs.pm/elixir/GenServer.html#c:handle_call/3)）／非同期処理（[handle_cast](https://hexdocs.pm/elixir/GenServer.html#c:handle_cast/2)）を選択できます

from @piacerex

https://qiita.com/piacerex/items/49c44d7a450c0400de91

# ⑥ Agent

上記GenServerのうち、状態を保持する部分を簡略化したものが [Agent](https://hexdocs.pm/elixir/Agent.html) です

from @kikuyuta さん

https://qiita.com/kikuyuta/items/2336bb83ed0ffb1bc47a

# ⑦ ETS／Registry

上記GenServerやAgentのような、1つの状態だけを保持するのでは無く、複数の状態をまとめて保持できるようにしたサーバープロセスが、インメモリDBである [ETS](https://hexdocs.pm/elixir/erlang-term-storage.html) や [Registry](https://hexdocs.pm/elixir/Registry.html) です

いずれも、単一マシン上でのローカルアクセスしか出来ませんので、複数マシンでの共有をしたい場合は、後述するMnesiaやRedixを使う必要があります

from @kikuyuta さん

https://qiita.com/kikuyuta/items/a05ce2516260d7ef27a3

# ⑧ GenStage

GenServerで作られたPubプロセス群に渡されたデータ／複数処理を、やはりGenServerで作られたSubプロセス群に非同期並行でバケツリレーするのが [GenStage](https://hexdocs.pm/gen_stage/GenStage.html) です

これにより、並行化されたPubSubが実現され、キューやバックプレッシャーを簡単に構築できます

from @twinbee さん

https://qiita.com/twinbee/items/12a61863ceef794996e0

https://qiita.com/twinbee/items/eda7f70fa9e4651f2248

# ⑨ Flow

上記GenStageを応用して、マルチコア並列データ処理のパイプラインをシンプルに実現するのが [Flow](https://hexdocs.pm/flow/Flow.html) です

リスト処理するEnumとほとんと同じ書き味で、データ処理を並列処理化できます

from @twinbee さん 

https://qiita.com/twinbee/items/43b767520da666ee960d

# ⑩ Broadway

上記GenStageを応用して、マルチコア並列データ処理をシンプルに実現するのが [Broadway](https://hexdocs.pm/broadway/introduction.html) です

GenStageによるPubSub／キュー処理を抽象化しつつ、QoSや障害時ハンドリング、外部キュー連携（Amazon SQS、Google Cloud PubSub、Kafka、RabbitMQ、AMQP、Redis、Redis Stream、Splunk）を加えることが出来ます

from @RyoWakabayashi さん 

https://qiita.com/RyoWakabayashi/items/68a06a7bd0e0d8d951b0

https://qiita.com/RyoWakabayashi/items/6a174768ca78df0b67fb

# ⑪ Mnesia

上記ETSをマルチクラスタ分散化し、冗長化と自動復旧を可能としたのが [Mnesia](https://elixirschool.com/ja/lessons/storage/mnesia) です

from @piacerex 

https://qiita.com/piacerex/items/5c6db095f4c567c36f69#%E3%83%9E%E3%83%AB%E3%83%81%E3%83%9E%E3%82%B9%E3%82%BFdb%E6%A7%8B%E7%AF%89

from @32hero さん

https://qiita.com/32hero/items/efae1dbd13b974153dd3

# ⑫ Redix

[Redix](https://hexdocs.pm/redix/Redix.html) は、インメモリDBであるRedisをElixirから使うアダプターです

from @koyo-miyamura さん

https://qiita.com/koyo-miyamura/items/acc93132c634bb4156a8

https://qiita.com/koyo-miyamura/items/b5c123fa40685b9f8073

# ⑬ Node／global／pg

[Nodeモジュール](https://hexdocs.pm/elixir/Node.html) は、マルチクラスタ分散化されたElixirノードを制御するためのモジュールです

遠隔地にあるプロセスとの通信を行う前のElixirノード間接続やその確認を行うのに使用します

マルチクラスタのプロセス名管理と分散ロックに [globalモジュール](https://www.erlang.org/doc/apps/kernel/global.html) が使われます

分散化されたプロセスのグループ管理に [pgモジュール](https://www.erlang.org/doc/apps/kernel/pg.html) が使われます

from @piacerex 

https://qiita.com/piacerex/items/b265049a5b21e41b1a8f

# ⑭ libcluster

TCP/IP上でのマルチクラスタ分散化されたElixirノードを実現するのが [libcluster](https://hexdocs.pm/libcluster/readme.html) です

下記ディスカバリ戦略を選択できます

- Gossip … スケーリングは固定
- EPMD … スケーリングは固定、Elixirネイティブ
- k8s … オートスケーリング、自己修復
- ECS統合 … オートスケーリング
- EC2統合 … オートスケーリング

from @mokichi さん

https://qiita.com/mokichi/items/c3157804faa295ce1574

from @mnishiguchi さん

https://qiita.com/mnishiguchi/items/e854de2626028b9ea830

# ⑮ dns_cluster

DNSをディスカバリ戦略としてlibclusterと同様のことを実現するのが [dns_cluster](https://hexdocs.pm/dns_cluster/DNSCluster.html) です

<iframe width="560" height="315" src="https://www.youtube.com/embed/Ckgl9KO4E4M?si=nJ9wWSNzQL2BbTJd&start=568" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

# ⑯ Rustler／Port／ErlPort／Protobuf／KafkaEx

いずれもElixirから他システムと連携するライブラリで、RustやPython等の他言語のシステムや、Kafka／ProtocolBuffer経由でのリモートシステムとの分散化を叶えます

from @piacerex　※ライブラリ紹介のみ

https://qiita.com/piacerex/items/7e4b15e4dd9a94e58b3b

# ⑰ grpcbox

ElixirでgRPCを行うことでも他システムと連携できますが、コレを叶えるライブラリが [grpcbox](https://github.com/tsloughter/grpcbox) です

https://github.com/tsloughter/grpcbox

# ⑲ Channel／LiveView

[Channel](https://hexdocs.pm/phoenix/channels.html) は、WebSocketによって、何百万ものクライアントとの同時接続とメッセージ交換を叶える仕組みで、HTTPベースのため高速では無いものの、複数クライアントで同一ステートを共有できる便利な分散システムです

Channelを土台とする [LiveView](https://hexdocs.pm/phoenix_live_view/welcome.html) も、Web SPAアーキテクチャであると同時に、複数クライアントで同一ステートを共有できます

from @piacerex 

https://qiita.com/piacerex/items/3f8ee18c9443d63955bf

# ⑱ FLAME

[FLAME](https://hexdocs.pm/flame/FLAME.html) は、Elixirの関数に対し、サーバーレス／FaaS同様のデマンド実行やスケーラビリティを実現するライブラリです

FLAMEは、サーバーレス／FaaSと比べ、既存システムのサーバーレス化／FaaS化のためのコード解体／再構成やマイクロ化が必要無く、サーバーレス／FaaSほど構成が複雑化しない点が大きなメリットです（詳細は下記コラムにて）

https://fly.io/blog/rethinking-serverless-with-flame/

from @kikuyuta さん

https://qiita.com/kikuyuta/items/0f1aefc9fc39dfc94fa1

# ⑳ Livebookノード

現在のElixirは、iexやバイナリイメージ、escriptだけで無く、Web上開発環境である [Livebook](https://livebook.dev/) 上で実行できますが、<font color="red">**Livebookは1つのElixirノードと同等に扱えるため、Livebook間やLivebook／iex間でのマルチクラスタ分散が可能**</font> です

なおLivebook 0.13以降からは、Elixirノードとしてだけに限らず、REST API／GraphQL APIサーバーやExcelパーサーとしても構築可能となり、ますます分散環境として魅力的になっています

from @piacere in [ElixirImp#31：Elixirで作ったもの、何でもLT会](https://fukuokaex.connpass.com/event/283391/)

<iframe width="560" height="315" src="https://www.youtube.com/embed/N1nbuGoa1ss?si=aDIcjcJ8F5Irbp0h" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>

# 終わりに

今回、ご紹介したElixirプロセス間通信／分散／並行は、過去／現在／未来のスキルからあなたのBright（輝き）とRight（正しさ）を引き出すプロダクト「Bright」でも、下図の通り、スキル判定対象になっています

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/155423/7d2122df-df50-3ea3-d1d6-d6bb82fb7a8c.png)

https://bright-fun.org/

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

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