Skip to content
Published on

モダン Elixir & Phoenix 2026 — Elixir 1.18 / Phoenix 1.8 / LiveView 1.0 / Oban / Broadway / Bumblebee / Nx / Livebook 徹底ガイド

Authors

プロローグ — 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"""
    <div>
      <h1>カウント: <%= @count %></h1>
      <button phx-click="inc" class="btn btn-primary">+</button>
    </div>
    """
  end
end

これで全部だ。100ms 以内にサーバ往復が起き、変わったテキストノードだけが patch される。JS は一行も書いていない。

4.2 1.0 の主な変更

  • Streams — 大量リストの効率的な更新。追加/削除/移動をサーバが宣言し、クライアントは DOM キーだけで処理する。無限スクロールのニュースフィードをメモリ爆発なしに作れる。
  • Async assignsassign_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.allRepo.insertRepo.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。

import Nx.Defn

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