필사 모드: モダン Elixir & Phoenix 2026 — Elixir 1.18 / Phoenix 1.8 / LiveView 1.0 / Oban / Broadway / Bumblebee / Nx / Livebook 徹底ガイド
日本語プロローグ — 30 年もののVM が 2026 年に再注目される理由
Elixir は新しい言語ではない。2012 年に José Valim が Erlang/OTP の上に人間にやさしい構文を載せて始めた。そしてその Erlang は 1986 年にエリクソンで電話交換機のために生まれた — つまり BEAM(Erlang VM)は実質 40 歳である。
2026 年、その 40 歳の VM があらためて注目されている。理由は一行で言える。
**「並行性・分散・耐障害性を初日から組み込んだ VM は BEAM だけで、マルチコア・リアルタイム・AI 推論の時代がついにそちらの形を強いている。」**
- **Elixir 1.18(2024 年 12 月)** — set-theoretic types の初プレビュー。漸進的静的型付けの道が開いた。
- **Phoenix 1.8(2024 年 12 月)** — Scope API で認証コンテキストを関数シグネチャに刻み、daisyUI と Tailwind v4 がデフォルトに。
- **LiveView 1.0(2024 年 11 月)** — 5 年超の 0.x ベータを経て、ついに正式 1.0。サーバ描画 HTML とリアルタイム双方向通信を一つの抽象に。
- **Bumblebee + Nx + Axon** — Hugging Face Transformer モデルを Elixir 上で動かし、GPU 加速まで効かせる。
- **Tidewave(2025 年 9 月)** — José Valim が公開した Elixir 用 LLM サービングプラットフォーム。BEAM 上で LLM を配る。
本稿は 2026 年の Elixir スタックを最初から最後まで — VM のアクターモデルから LiveView、Oban、Broadway、Membrane、Bumblebee、Tidewave、そして韓国・日本の採用事例まで — 一読でまとめる。
1 章・なぜ BEAM か — アクター・ソフトリアルタイム・耐障害性
最初にはっきりさせる。Elixir が魅力的な理由の半分は **言語そのもの** ではなく、**その下の VM** にある。
BEAM の三本柱。
1. **軽量プロセス(アクター)** — 一ノードに数百万のプロセスが共存する。各プロセスはメモリ(既定で約 2 KB のヒープ)とメールボックスを持つ独立した単位。OS スレッドではない。
2. **プリエンプティブスケジューリング** — スケジューラが一定 reduction ごとにプロセスを強制スワップする。一つのプロセスが無限ループしても他が餓死しない — これが「ソフトリアルタイム」。
3. **let it crash + スーパーバイザツリー** — プロセスが死ぬと隔離単位の中で死に、上のスーパーバイザがあらかじめ宣言した戦略(one_for_one、rest_for_one ほか)で再起動する。防御コードの代わりに回復コードを書く。
絵にするとこうなる。
[Application Supervisor]
|
+-------------+-------------+
| | |
[DB Pool Sup] [Web Sup] [Worker Sup]
| | |
[Pool Worker] [Endpoint] [Job Worker x N]
|
[LiveView Conn x M]
このツリー一枚で Elixir アプリの運用はほぼ説明がつく。LiveView 接続が一つ落ちてもその接続だけが死ぬ。DB プールが揺らげば Pool Sup が立て直す。ワーカーが OOM すれば Worker Sup が新しいのを立てる。
**覚える一行**:「BEAM は死なない VM ではなく、**死んでも大丈夫な** VM である。」
2 章・Elixir 1.18(2024 年 12 月)— set-theoretic types プレビュー
2024 年 12 月 19 日にリリースされた Elixir 1.18 は、それ自体で十分大きな出来事である。
2.1 set-theoretic types — 漸進的静的型付けへの一歩
長年 Elixir 利用者からの最頻質問は「なぜ静的型がない」だった。答えは (1) Dialyzer がある (2) BEAM の並行性とホットコードリロードは動的型と相性が良い、の 2 つだった。コアチームはその答えがもう十分でないと判断した。
1.18 は本格的な答えの第一歩である。set-theoretic types を関数シグネチャとパターンマッチに適用し始めた。union(`A or B`)・intersection(`A and B`)・negation(`not A`)を第一級として扱う型システム。
コンパイラが自動推論 — アノテーションなしで
defmodule Numbers do
def add(x, y) when is_integer(x) and is_integer(y), do: x + y
def add(x, y) when is_float(x) and is_float(y), do: x + y
end
不正な呼び出しはコンパイル時に検出
Numbers.add(1, 2.0)
warning: incompatible types — integer/float の組のいずれにも属さない
今はとても限定的な範囲(シグネチャ・パターンマッチ・一部ガード)だが、ロードマップ上は 1.19〜1.20 で本格的な型注釈構文が入る。
2.2 mix の改善
1.18 は mix にも手を入れた。`mix test --partitioned` が安定化、`mix format` が prettier 風に import 整列まで対応、`mix deps.tree` が SAT ソルバ診断を出して依存衝突の原因を示す。
2.3 Elixir のバージョン方針
Elixir は意図的に 1.x を長く引っ張る。2.0 が出る可能性は低い。代わりに毎年 12 月に 1.x のマイナーリリースを出す — 1.15(2023)、1.16(2024 初頭)、1.17(2024 中頃)、1.18(2024 末)、1.19 は 2025 年 12 月予定。
3 章・Phoenix 1.8(2024 年 12 月)— Scope API、daisyUI デフォルト
Phoenix は Elixir の標準 Web フレームワーク。Rails の比喩で入る — コントローラ・ビュー・ルータの構造は似ている — が、核は別物。Phoenix は **LiveView を一級** に置き、**Plug** ミドルウェアの上に乗り、**PubSub** でノード間メッセージをルーティングする。
3.1 Scope API — 認証コンテキストを関数シグネチャに刻む
1.8 の目玉は Scope。従来は認証済みユーザを `conn.assigns.current_user` から取り出し、これがコントローラ内でしか使えなかった。Scope はそのユーザ(と所属する organization や tenant)を第一引数として明示的に受ける。
defmodule MyApp.Posts do
alias MyApp.Accounts.Scope
スコープを第一引数に — 認証コンテキストがシグネチャに刻まれる
def list_posts(%Scope{user: user, org: org}) do
Post
|> where(org_id: ^org.id)
|> where(author_id: ^user.id)
|> Repo.all()
end
def create_post(%Scope{} = scope, attrs) do
%Post{}
|> Post.changeset(attrs)
|> Ecto.Changeset.put_change(:org_id, scope.org.id)
|> Repo.insert()
end
end
なぜ重要か? **コントローラだけでなく、LiveView、Oban ジョブ、バックグラウンドタスク、GenServer まで同じ認証コンテキストを一貫して受け取れる。** 従来は LiveView が mount で user を別途 assign しなければならず、Oban ジョブは args に user_id を入れて再 fetch する必要があった。
3.2 daisyUI + Tailwind v4 がデフォルト
1.8 から `mix phx.new` の既定 UI スタックは Tailwind v4 + daisyUI。Heroicons も既定。特別な設定なしに即座にモダンな UI が立つ。
1.8 既定テンプレート
<.button class="btn btn-primary" phx-click="save">保存</.button>
<.input field={@form[:title]} class="input input-bordered" />
以前は Tailwind だけで、コンポーネントは自作だった。1.8 は daisyUI のコンポーネントクラス(btn、card、modal、alert など)を即使える。
3.3 新規プロジェクト作成
mix archive.install hex phx_new
mix phx.new my_app --live # LiveView 同梱
cd my_app
mix ecto.create
mix phx.server
この 4 行で LiveView・Tailwind v4・daisyUI・Ecto・Postgres が揃ったプロジェクトが 4000 番ポートで立ち上がる。
4 章・LiveView 1.0 — 5 年のベータの先にある正式リリース
LiveView は Elixir の代表技術である。2018 年の ElixirConf で Chris McCord がデモして以来、5 年超の 0.x ベータを経て 2024 年 11 月に 1.0 が正式リリースされた。
4.1 LiveView が解く問題
既存の SPA(React、Vue)スタックの恒常的コストは 2 つ。
1. **API を二度作る** — REST/GraphQL バックエンド + それを呼ぶフロント。
2. **状態同期** — サーバ状態とクライアント状態が分かれ、その差がバグの根源。
LiveView はこの両方を消す。**状態はサーバだけにある。UI はサーバで描画した HTML が WebSocket でプッシュされる。** ユーザイベント(click、submit、keypress)は WebSocket でサーバに戻り、サーバが状態を変更して変わった DOM の一部だけを再 push する。
defmodule MyAppWeb.CounterLive do
use MyAppWeb, :live_view
def mount(_params, _session, socket) do
{:ok, assign(socket, count: 0)}
end
def handle_event("inc", _params, socket) do
{:noreply, assign(socket, count: socket.assigns.count + 1)}
end
def render(assigns) do
~H"""
"""
end
end
これで全部だ。100ms 以内にサーバ往復が起き、変わったテキストノードだけが patch される。JS は一行も書いていない。
4.2 1.0 の主な変更
- **Streams** — 大量リストの効率的な更新。追加/削除/移動をサーバが宣言し、クライアントは DOM キーだけで処理する。無限スクロールのニュースフィードをメモリ爆発なしに作れる。
- **Async assigns** — `assign_async(:user, fn -> ... end)` で非同期データ読み込みが一級市民に。Suspense ライクな UX。
- **Function components + slots** — React の children prop と同じスロットパターンが安定化。
- **JS Commands** — 単純なトグル/非表示/フォーカスはサーバ往復なしに `JS.toggle("#menu")` のようなクライアント側コマンドで処理。
4.3 LiveView が向かないケース
LiveView は万能ではない。
- **オフラインファースト PWA** — WebSocket が切れたら使えない。
- **極端にインタラクティブな UI** — 60fps ドラッグ/スクラブのようなミリ秒応答はクライアント側が良い。
- **CDN エッジ描画** — サーバ状態が必要なのでエッジに散らしにくい。
そういう場合は **LiveView Hooks** で一部をクライアント JS に出すか、いっそ React へ。
5 章・Ecto — DB 層の標準
Ecto は Elixir の ORM ではなく **DB クエリ・検証・マイグレーションのライブラリ** である。ActiveRecord 比較は表面的で、本質は別物。
Ecto の 4 モジュール。
1. **Repo** — DB プールと実行インタフェース。`Repo.all`、`Repo.insert`、`Repo.transaction`。
2. **Schema** — テーブルと Elixir 構造体のマッピング。ActiveRecord と違い **モデルではなくマッピングだけ**。
3. **Changeset** — 入力の検証・変換のパイプライン。これが Ecto の真の武器。
4. **Query** — コンパイル時に検査される DSL。生 SQL より安全。
5.1 Changeset — 真の武器
Changeset は「この入力を受け、これらの検証を経て、この形で DB に入れる」を一つのパイプラインで表す。
def changeset(post, attrs) do
post
|> cast(attrs, [:title, :body, :published_at])
|> validate_required([:title, :body])
|> validate_length(:title, min: 3, max: 200)
|> validate_format(:title, ~r/^[^<>]+$/)
|> unique_constraint(:slug)
|> put_change(:slug, slugify(attrs["title"]))
end
これは単なるフォーム検証ではない。**すべての DB 書き込みが changeset を経由する。** だからビジネスルール違反はコンパイル時ではなくデータ層の一箇所で遮断される。
5.2 Multi — トランザクションビルダー
複雑なトランザクションは `Ecto.Multi` で。
Multi.new()
|> Multi.insert(:post, Post.changeset(%Post{}, attrs))
|> Multi.update(:user, User.bump_post_count(user))
|> Multi.insert(:notification, fn %{post: post} ->
Notification.new_post(post)
end)
|> Repo.transaction()
各段階は前段の結果を読め、どこかで失敗すれば全体がロールバックされる。
5.3 Ecto 3 — 安定の標準
2024〜2026 年の Ecto は安定期。3.x が事実上の標準で、大きな変化はなく漸進的な改善が続く。Postgres の配列・jsonb・LISTEN/NOTIFY、MySQL 8、SQLite — どれもよくサポートされている。
6 章・Oban — ジョブ処理と「Pro 999 ドル」騒動
Oban は Elixir 界隈の標準ジョブキュー。**Postgres ベース** が核 — Sidekiq のように Redis を別途立てず、すでにある Postgres にジョブ用テーブルを一つ足す。
6.1 なぜ Postgres ベースか
- **ビジネスデータと ジョブ enqueue が同一トランザクションでコミットされる。** Sidekiq は「Redis にキュー入れて DB にデータ保存」の間に失敗するとデータだけ/ジョブだけが残る。Oban は両方同じトランザクション。
- **運用インタフェースが SQL。** ジョブ状態をクエリで直接見る。別途の管理 UI が必須ではない。
- **バックアップ・レプリケーション・HA が Postgres そのまま。** ジョブキュー専用インフラがない。
ジョブ定義
defmodule MyApp.Workers.EmailWorker do
use Oban.Worker, queue: :emails, max_attempts: 5
@impl Oban.Worker
def perform(%Oban.Job{args: %{"user_id" => user_id, "kind" => kind}}) do
user = Repo.get!(User, user_id)
MyApp.Mailer.deliver(user, kind)
:ok
end
end
ビジネスロジックと同じトランザクションで enqueue
Multi.new()
|> Multi.insert(:user, User.changeset(%User{}, attrs))
|> Oban.insert(:email_job, fn %{user: user} ->
EmailWorker.new(%{user_id: user.id, kind: "welcome"})
end)
|> Repo.transaction()
6.2 Oban Pro 999 ドル騒動
Oban 本体は無料/OSS。だが運用でよく必要になる機能 — Cron、Batch Jobs(N 個のジョブが全部終わったらコールバック)、Workflow、Smart Engines — は Pro 側にある。2024 年中頃に Pro のシングルライセンス価格が **年 999 ドルに引き上げ** られ、コミュニティが騒いだ。
賛否はあった。
- **賛成側** — Oban メンテナ一人がフルタイムで張り付くからこそ BEAM 界隈にこの品質のジョブキューが維持される。年 999 ドルはシニア時給 1〜2 時間ぶん。
- **反対側** — Sidekiq Pro は年 219 ドル。999 ドルは高すぎるし、Pro 限定機能の一部は OSS にすべきだった。
結局コミュニティは Pro 派、OSS 本体だけで自作派、Quantum + 自前 GenServer 派に分かれた。2026 年時点では **新規プロジェクトはほぼ Pro を買う** — 年 999 ドルはエンジニア数日ぶんの価値しかない。
7 章・Broadway — Kafka・RabbitMQ・AMQP・SQS パイプライン
Oban が「DB ジョブキュー」なら Broadway は「データパイプライン」。外部メッセージシステム(Kafka、RabbitMQ、AMQP、AWS SQS、Google PubSub)からメッセージを引き、バッチ処理し、バックプレッシャを管理する抽象。
7.1 Broadway が解く問題
ストリーミングデータ処理に必要なのは以下。
1. **コンシューマグループ** — 複数ノードが同じトピックを分担して読む。
2. **バッチ処理** — 1 件ずつではなく 100/1000 件単位でまとめて処理。
3. **バックプレッシャ** — 下流が遅ければ上流から取らない。
4. **リトライ/デッドレター** — 失敗メッセージの隔離。
Broadway はこれを BEAM の GenStage の上にすべて載せた標準解。
defmodule MyApp.KafkaPipeline do
use Broadway
def start_link(_opts) do
Broadway.start_link(__MODULE__,
name: __MODULE__,
producer: [
module: {BroadwayKafka.Producer, [
hosts: [localhost: 9092],
group_id: "my_group",
topics: ["events"]
]},
concurrency: 1
],
processors: [
default: [concurrency: 10]
],
batchers: [
default: [batch_size: 100, batch_timeout: 1_000]
]
)
end
@impl true
def handle_message(_, message, _) do
メッセージ 1 件を変換
message
end
@impl true
def handle_batch(:default, messages, _, _) do
100 件まとめて DB INSERT
Enum.map(messages, &Message.update_data(&1, transformed(&1)))
end
end
これで全部だ。Kafka・RabbitMQ・SQS・PubSub は producer モジュールを差し替えるだけ。
7.2 事例 — イベント ETL
EC プラットフォームで注文イベント(毎秒数千件)を Kafka から読み、エンリッチして ClickHouse に取り込むパイプライン。Broadway で書くと BEAM 一ノードで producer 1、processor 64、batcher 8 で毎秒万件級を余裕で捌く。ノードを足せばコンシューマグループがパーティションを自動再分配する。
8 章・Membrane — 音声/動画パイプライン
Membrane は Software Mansion 社が作る音声/動画処理フレームワーク。WebRTC SFU(Jitsi/LiveKit のようなもの)からライブストリーミングのトランスコード、RTSP カメラ統合、HLS セグメント生成までやる。
8.1 なぜ BEAM がメディア処理に合うか
- **同時ストリーム数千** — 各ストリームが独立プロセス。一通話が切れても他に影響なし。
- **バックプレッシャ組み込み** — 処理が遅い段があれば前段は送らない。
- **分散** — 複数ノード間で負荷分散が自然。
もちろんコーデック(H.264/VP9/Opus)自体のエンコード・デコードは C/Rust(NIF)に落ちる。Membrane はそのパイプラインを組み、ライフサイクルを管理し、流量を制御する。
8.2 シンプルなパイプライン
defmodule MyApp.AudioPipeline do
use Membrane.Pipeline
@impl true
def handle_init(_ctx, opts) do
structure = [
child(:file_src, %Membrane.File.Source{location: opts.input}),
child(:mp3_decoder, Membrane.MP3.MAD.Decoder),
child(:opus_encoder, %Membrane.Opus.Encoder{}),
child(:rtp, Membrane.RTP.PayloadFormatResolver),
child(:udp_sink, %Membrane.UDP.Sink{destination: opts.dest})
]
{[spec: structure], %{}}
end
end
MP3 ファイルをデコードして Opus に再エンコード、RTP でパケット化して UDP で送る。各ノードは独立プロセスでバックプレッシャが自動で流れる。
8.3 実際の使われ方
- **Jellyfish** — Membrane チーム製の WebRTC SFU サーバ。Zoom 的な多人数会議を BEAM 上で。
- **Veedo** — Membrane ベースのライブストリーミングプラットフォーム。
9 章・Igniter — コード変換ツール
Igniter は比較的新しい(2024 年)プロジェクト。Elixir コードを安全に自動修正するツールで、ライブラリのインストール/アップグレード時に必要なボイラープレートを自動で挿し込む。
9.1 何を解くか
従来の `mix deps.get` はライブラリを落とすだけ。それを使うには `config/config.exs` に設定を書き、`application.ex` に supervisor child を加え、router に plug を追加する — これを全部 README を読んで手でやっていた。
Igniter はこれを自動化する。ライブラリが Igniter Recipe を提供すれば、`mix igniter.install <lib>` が AST レベルで安全に全ファイルを修正する。
mix igniter.install ash_authentication
config/config.exs を自動修正
lib/my_app/application.ex に supervisor child を自動追加
lib/my_app_web/router.ex にルートを自動追加
9.2 直接使うケース
Igniter は単純なライブラリインストールだけでなく、マイグレーションツールとしても使う — 例えば LiveView 0.20 から 1.0 へ移行する際、deprecated API を自動変換する。Phoenix 1.7 → 1.8 マイグレーションの一部も Igniter recipe で提供される。
10 章・Bumblebee — Elixir で HF Transformers
ここから「Elixir も AI をやる」の話になる。
Bumblebee は Hugging Face Transformers の Elixir 移植。同じモデルアーティファクト(safetensors)と同じトークナイザ設定をそのまま読み、Elixir から推論する。
10.1 BERT を一行で推論
{:ok, model} = Bumblebee.load_model({:hf, "bert-base-uncased"})
{:ok, tokenizer} = Bumblebee.load_tokenizer({:hf, "bert-base-uncased"})
serving = Bumblebee.Text.fill_mask(model, tokenizer)
Nx.Serving.run(serving, "The capital of [MASK] is Paris.")
=> [%{token: "France", score: 0.97}, ...]
これで全部。CPU でも普通に動く。GPU 加速したければバックエンドを EXLA(XLA、JAX のあれ)に切り替える。
10.2 バックエンド — Nx → EXLA / Torchx
Bumblebee 自体は Nx の上に乗っている。Nx は NumPy ライクなテンソル API。実際の計算はバックエンドが担う。
- **EXLA** — Google XLA を介した CPU/GPU/TPU。速いものが多い。
- **Torchx** — LibTorch(PyTorch コア)を介した CPU/GPU。PyTorch モデル互換性が良い。
config/config.exs
config :nx, default_backend: EXLA.Backend
config :nx, default_defn_options: [compiler: EXLA]
10.3 Stable Diffusion、Whisper、Llama
Bumblebee が対応するモデル群は着実に増えた。
- **Stable Diffusion XL** — テキスト → 画像。
- **Whisper** — 音声 → テキスト。ライブ字幕によく使う。
- **Llama 3、Mistral、Gemma** — 7B〜70B の LLM。量子化でノート PC でも動く。
- **CLIP** — 画像/テキスト埋め込み。
10.4 Phoenix と組み合わせる — Nx.Serving
Bumblebee の推論は `Nx.Serving` という抽象の中で走る。これが決定的 — Phoenix アプリの supervisor ツリーに child として置くだけで、自動で **バッチ/キューイング/タイムアウト** を処理してくれる。
application.ex
children = [
MyAppWeb.Endpoint,
{Nx.Serving,
serving: build_whisper_serving(),
name: WhisperServing,
batch_size: 8,
batch_timeout: 200}
]
どこからでも呼ぶ
Nx.Serving.batched_run(WhisperServing, audio_input)
10 件の同時リクエストが来ても `batch_size: 8` が自動で 8 件ずつまとめて GPU に投げる。GPU 使用率が上がる。
11 章・Nx + Axon + Explorer — BEAM データサイエンス
Bumblebee の一行推論を見たので、その下の層を見る。
11.1 Nx — NumPy for BEAM
Nx はテンソルライブラリ。NumPy/PyTorch に近い API。
defn softmax(t) do
Nx.exp(t) / Nx.sum(Nx.exp(t))
end
Nx.tensor([1.0, 2.0, 3.0]) |> softmax()
=> Nx.Tensor f32[3] [0.09, 0.24, 0.67]
`defn` は **数値専用関数**。普通の Elixir 関数ではなく JIT コンパイルされる — EXLA で XLA に下りて GPU/TPU で動く。
11.2 Axon — ディープラーニングライブラリ
Axon は Nx の上のニューラルネットワークライブラリ。Keras スタイルの関数型 API。
model =
Axon.input("input", shape: {nil, 784})
|> Axon.dense(128, activation: :relu)
|> Axon.dropout(rate: 0.2)
|> Axon.dense(10, activation: :softmax)
学習
model
|> Axon.Loop.trainer(:categorical_cross_entropy, :adam)
|> Axon.Loop.metric(:accuracy)
|> Axon.Loop.run(train_data, %{}, epochs: 10)
小さなモデルは BEAM ノードで直接学習する。大きなモデルは PyTorch で学習し Bumblebee で配るのが定石。
11.3 Explorer — DataFrame、Polars バックエンド
Explorer は Pandas/Polars の Elixir 版。**内部的に Polars(Rust)を NIF で呼ぶ。** だから速い。
require Explorer.DataFrame, as: DF
df = DF.from_csv!("sales.csv")
df
|> DF.filter(col("amount") > 100)
|> DF.group_by("region")
|> DF.summarise(total: sum(col("amount")), n: count(col("id")))
|> DF.sort_by(desc: "total")
これを Livebook で可視化すれば Jupyter 相当のデータ分析環境になる。
12 章・Livebook — Elixir ノートブック
Livebook は José Valim 製の Elixir 版 Jupyter。ただし Jupyter と違う点が 2 つある。
1. **コラボレーションが一級** — 一つのノートブックを複数人で同時編集。Google Docs 的。
2. **バージョン管理がクリーン** — ノートブックは `.livemd`(markdown)。`git diff` が人間に読める。
Mac/Linux 一行インストール
mix escript.install hex livebook
livebook server
http://localhost:8080
12.1 Livebook が合う場所
- **データ探索** — DB クエリ、Explorer、Vega-Lite チャート。
- **ML 推論実験** — Bumblebee モデルをノートブックで立ててハイパーパラメータ調整。
- **運用ノートブック** — 「プロダクション DB にこのクエリを一度走らせたい」をレビュー可能な形で。
- **チュートリアル/教材** — `.livemd` は実行可能な文章。
12.2 Smart Cells
Smart Cell は UI フォームでコードを生成するセル。チャート、DB クエリ、ニューラルネット可視化などがフォーム入力だけで該当コードセルを生成する。
[Smart Cell: SQL Query]
Connection: prod_replica
Query: SELECT * FROM users WHERE created_at > $1
Variables: cutoff_date = ~D[2026-01-01]
→ セル下に Ecto/Postgrex コードが自動生成される
13 章・Tidewave(2025 年 9 月、José Valim)— Elixir LLM サービング
2025 年 9 月、José Valim と Dashbit チームが **Tidewave** を公開した。「BEAM 上の LLM サービングプラットフォーム」だ。
13.1 何を解くか
LLM サービングに必要なのは以下。
1. **同時推論リクエスト数百〜数千を GPU にうまく束ねる** — vLLM が解く問題。
2. **ストリーミング応答** — トークン単位でクライアントに push。
3. **セッション/状態管理** — マルチターン会話、コンテキスト。
4. **障害隔離** — 一ユーザの不正リクエストが他に影響しない。
5. **分散** — 複数 GPU ノードにルーティング。
このうち 3・4・5 は **BEAM が 30 年前から得意な領域**。1・2 も Nx.Serving + Phoenix Channels の上に自然に乗る。
13.2 アーキテクチャ
Tidewave はだいたいこんな形。
[Phoenix Endpoint]
|
+-------+-------+
| |
[HTTP /chat] [WS /stream]
| |
v v
[Session Sup] [Stream Channel]
| |
v v
[Session GenServer x N]
|
v
+---------+---------+
| |
[Nx.Serving] [Tool Runtime]
| |
v v
[GPU Workers] [DB / HTTP / RAG]
各ユーザセッションは独立した GenServer。一つが壊れても他に影響しない。Nx.Serving が GPU バッチを管理する。ツール呼び出しは別の supervisor サブツリー。
13.3 vLLM 比較
Tidewave は vLLM と正面衝突するというより **別の問題を解く**。vLLM は GPU 効率で群を抜く。Tidewave は GPU 効率は vLLM に及ばないが、**運用性・セッション管理・障害隔離・分散** が BEAM の強み。
選定基準はシンプル。
- **単一ノードで短い応答を最大スループットで** — vLLM。
- **多セッション・長時間会話・複雑なツール呼び出し・高可用性** — Tidewave。
14 章・BEAM 運用 — Observer、recompile、ホットリロード
Elixir アプリを運用した人だけが知る楽しみがいくつかある。
14.1 Observer — ライブノードを覗く
iex --sname dev --remsh my_app@hostname
iex> :observer.start()
GUI が立つ。プロセスツリー、メールボックス長、メモリ使用量、CPU スケジューラ状態 — すべてライブで見える。あるプロセスのメールボックスが異常に長ければそこにボトルネックがある。
14.2 IEx リモートシェル
iex --sname remote@host --cookie SECRET --remsh prod@host
プロダクションノードへリモート IEx シェルを張る。そこで `Repo.get(User, 1)`、`Phoenix.PubSub.broadcast(...)` 全部できる。**運用デバッグの極み。**
14.3 ホットコードリロード
iex> r MyApp.SomeModule
稼働中のノードにモジュールを再コンパイル/再ロードする。全体再起動なしに一関数だけ差し替えても即反映。**ただしプロダクションでは慎重に。** 普通は新リリースを切ってローリング再起動する。
15 章・韓国・日本での Elixir 採用
Elixir は巨大企業のメインスタックではないが、特定領域で強い。
15.1 韓国
- **Toss(トス)** — フィンテックのメインスタックは Kotlin/JVM だが、一部のリアルタイム系統(通知、チャット、一部決済ワークフロー)に Elixir/Phoenix が入っているとされる。
- **BabyDragon(ベビードラゴン)** — 韓国モバイルゲーム会社。Elixir/Phoenix をゲームバックエンドとマッチメイキングサーバに広範に使う。
- **Banksalad** — 家計簿アプリ。初期に一部バックエンドを Elixir でやったとされる資料がある。
- **個人開発者/スタートアップ** — リアルタイムチャット・コラボ・ゲームバックエンドを単一 BEAM ノードで捌く小チームが安定して存在する。
韓国での Elixir 普及は遅め。第一の理由は **採用プールが小さい** こと。JVM/Kotlin/Node に比べて韓国語資料も少ない。ただし一度採用したチームは離れにくい。
15.2 日本
- **ドリコム** — モバイルゲーム会社。ゲームサーバ一部に Elixir/Phoenix。
- **DMM** — 一部のリアルタイム系統。
- **任天堂** — 公式発表は少ないが、一部オンラインサービスのバックエンドに BEAM 系(Erlang を含む)が入っているとされる。
- **Cookpad** — Ruby 本拠地だが、一部バックエンド実験で Elixir を見る資料がある。
- **サイバーエージェント** — 広告/AdTech のリアルタイム部分。
日本は Erlang の伝統が早くからあった(NTT・エリクソン日本の影響)。なので Elixir への移行が韓国より自然。日本語資料(Qiita、Zenn)も韓国語より豊富。
15.3 世界
- **Discord** — Erlang/Elixir でメッセージルーティング。一チャネル数百万同時接続を BEAM クラスタで処理。
- **WhatsApp** — Erlang。Meta 買収前まで小規模チームで数億ユーザを運用した伝説。
- **Pinterest** — 一部の通知/SMS 系統。
- **Heroku** — ルーティング層を一時 Erlang で。
- **Bleacher Report** — トラフィックスパイク対応を Elixir 一本で。
16 章・誰が Elixir を選ぶべきか
最終章。決定マトリクス。
Elixir/Phoenix がよく合うケース
1. **リアルタイム並行性が核** — チャット、ゲーム、ライブストリーム、コラボツール、トレーディング。
2. **長期接続を多数維持** — WebSocket 数万本、IoT デバイス数万台。
3. **ソフトリアルタイム・耐障害性が要件** — 通信、決済通知、メディア。
4. **小チームでフルスタックを素早く** — LiveView 一抽象でバック+フロントを同時処理。
5. **メッセージパイプライン** — Broadway で Kafka/SQS/RabbitMQ ETL。
Elixir が合わないケース
1. **CPU 集約的な重い単発計算** — JS エンジン/ネイティブより BEAM は遅い。NIF で逃げられるが、単純な処理は Go/Rust の方が良い。
2. **巨大な ML 学習のメインスタック** — PyTorch エコシステムが圧倒的。Elixir はサービング/MLOps の補助に近い。
3. **豊富なライブラリエコシステムが核** — npm/PyPI のような量はない。Hex パッケージ数は万単位。
4. **採用/チーム編成が一番の制約** — 韓国で Elixir のシニアを短期間に 5 人雇うのは難しい。
一行ガイド
**「同時接続 1 万以上、もしくはリアルタイムが核、もしくは運用安定性が最優先なら Elixir は検討に値する。CRUD 中心の SaaS なら Phoenix は魅力的だが、Rails/Django/Next でも十分うまくいく。」**
17 章・参考 / References
- Elixir 公式: https://elixir-lang.org/
- Elixir 1.18 リリースノート: https://elixir-lang.org/blog/2024/12/19/elixir-v1-18-0-released/
- Phoenix Framework: https://www.phoenixframework.org/
- Phoenix 1.8 リリースノート: https://www.phoenixframework.org/blog/phoenix-1.8-released
- Phoenix LiveView: https://github.com/phoenixframework/phoenix_live_view
- LiveView 1.0 発表: https://www.phoenixframework.org/blog/phoenix-liveview-1.0-released
- Ecto: https://github.com/elixir-ecto/ecto
- Oban: https://github.com/oban-bg/oban
- Oban Pro: https://oban.pro/
- Broadway: https://github.com/dashbitco/broadway
- Membrane Framework: https://membrane.stream/
- Igniter: https://github.com/ash-project/igniter
- Bumblebee: https://github.com/elixir-nx/bumblebee
- Nx: https://github.com/elixir-nx/nx
- Axon: https://github.com/elixir-nx/axon
- Explorer: https://github.com/elixir-explorer/explorer
- Livebook: https://livebook.dev/
- Tidewave: https://tidewave.ai/
- Dashbit(José Valim の会社): https://dashbit.co/
- Fly.io Elixir ガイド: https://fly.io/docs/elixir/
- The BEAM Book(VM 内部): https://github.com/happi/theBeamBook
- Erlang Solutions ブログ: https://www.erlang-solutions.com/blog/
- ElixirConf US: https://elixirconf.com/
- ElixirConf EU: https://www.elixirconf.eu/
- Code BEAM: https://codebeamamerica.com/
- ElixirForum: https://elixirforum.com/
- Awesome Elixir: https://github.com/h4cc/awesome-elixir
- Thinking Elixir ポッドキャスト: https://thinkingelixir.com/
- BeamCommunity Slack: https://erlef.org/slack-invite
- Discord エンジニアリングブログ: https://discord.com/category/engineering
- WhatsApp Erlang 事例(過去): https://www.erlang-factory.com/upload/presentations/558/efsf2012-whatsapp-scaling.pdf
- ドリコム TechCon Elixir トラック: https://tech.drecom.co.jp/
- Toss 技術ブログ: https://toss.tech/
- BabyDragon: https://babydragon.com/
현재 단락 (1/383)
Elixir は新しい言語ではない。2012 年に José Valim が Erlang/OTP の上に人間にやさしい構文を載せて始めた。そしてその Erlang は 1986 年にエリクソンで電話...