LabHub

ブログ

モダン Erlang と BEAM 2026 — OTP 27 / OTP 28 プレビュー / Cowboy 3 / Bandit / Khepri / Gleam / Nerves / AtomVM 徹底ガイド

한국어English日本語

プロローグ — なぜ 30 年もののバーチャルマシンが 2026 年でも魅力的なのか

1986 年。エリクソンの通信スイッチチームが新言語を作る。名前は Erlang。目的はただ一つ — 死なないシステム。9 個の 9、つまり 99.9999999% の可用性を持つ電話交換機。

それから 40 年。2026 年の Erlang はもう通信会社の言語ではない。WhatsApp は 20 億人のメッセージを BEAM の上でさばき、Discord は数億人の音声・テキストを Elixir でルーティングし、Klarna は決済トランザクションを Erlang で処理している。RabbitMQ は事実上あらゆるマイクロサービスのバックボーンに敷かれ、Akamai の DNS は Erlang で動く。

BEAM は止まっていない。 2024 年 5 月に OTP 27 が出て、OTP 28 がプレビューから安定版へ向かう。Cowboy 3 が HTTP/2 と WebSocket を再仕上げし、Bandit が純 Elixir で Cowboy の代替を示した。RabbitMQ チームは Mnesia 後継となる Khepri を Raft の上に作った。Gleam は静的型を引っ提げて BEAM エコシステムに合流、Nerves は組み込み、AtomVM は ESP32 マイコンまで侵入した。

この記事は 2026 年の BEAM エコシステムの 全体地図 である。OTP 27/28 の新機能、HTTP スタック、分散データ、組み込み、新しい言語、そして誰が実際に使っているか。

「Erlang は私たちに、より少ない人数でより多くのことをさせてくれた。」 — Jan Koum、WhatsApp 共同創業者。50 人のエンジニアで 9 億ユーザーを運用していた頃。


第 1 章 · 2026 年の Erlang/BEAM 地図 — なぜ今も魅力的か

まず BEAM とは何か、なぜ他のバーチャルマシンと本質的に違うのかを整理する。

BEAM の 4 つの中核資産

  1. 軽量プロセス(グリーンプロセス) — OS スレッドではない。BEAM 内部の仮想プロセス。1 個あたり約 300 バイト。単一ノードで数百万個が起動できる。
  2. プリエンプティブスケジューラ — Go の協調型スケジューラとは違う。BEAM はリダクションカウントで強制的にコンテキストスイッチをする。1 つのプロセスが無限ループを回しても、ほかのプロセスが餓死しない。
  3. share-nothing のメッセージパッシング — プロセス間でメモリを共有しない。通信はすべてメッセージ。ロックがない。デッドロックのカテゴリ自体が消える。
  4. OTP (Open Telecom Platform) — supervisor、gen_server、gen_statem のような振る舞い(behavior)。30 年検証された分散・耐障害ライブラリの標準集。

BEAM が輝く領域と輝かない領域

輝く                                       輝かない
────────────────────────                  ────────────────────
大量の同時接続(数百万)                   数値計算 (CPU バウンド)
リアルタイムメッセージング・チャット       単一スレッドのスループット
分散システム・クラスタリング              機械学習の学習(training)
長寿命の接続 (LiveView)                   デスクトップ GUI アプリ
障害耐性が必須のシステム                   システムプログラミング
プロトコルゲートウェイ (MQTT, AMQP)        ゲームエンジン

要点: CPU ではなく、同時実行性(concurrency)がボトルネックになる場所。そして 死んではいけない場所

2026 年の BEAM エコシステム一枚絵

              ┌────────────────────────────────────────┐
              │             BEAM VM                    │
              │      (JIT, ETS, supervisor, OTP)       │
              └───────┬────────────────┬───────────────┘
                      │                │
        ┌─────────────┼───┐    ┌───────┼──────────┐
        │             │   │    │       │          │
     Erlang        Elixir gleam    Lustre     Phoenix
       │              │     │       (web)   (LiveView)
       │              │     │
       ▼              ▼     ▼
  ┌────────┐     ┌─────────┐  ┌─────────┐
  │Cowboy 3│     │ Bandit  │  │ AtomVM  │
  │  HTTP  │     │(Plug用) │  │ (ESP32) │
  └────────┘     └─────────┘  └─────────┘

  ストレージ:  Mnesia / Khepri (Raft) / ETS / DETS
  分散:        distributed Erlang / partisan
  組み込み:    Nerves (Linux) / AtomVM (MCU)
  財団:        Erlang Ecosystem Foundation (EEF)

以下、この地図の各部分を順に見ていく。


第 2 章 · Erlang/OTP 27 (2024 年 5 月) — 文字列補間と persistent_term の再発見

2024 年 5 月、Erlang/OTP 27 が正式リリースされた。2026 年現在、本番の大半は 27 へ移動中か既に移動済み。27 がもたらした、もっとも目立つ 3 つの変化。

2-1. トリプルクオート文字列 + 文字列補間

Erlang は 30 年間、文字列補間を持たなかった。2026 年でようやく追加された。しかも 2 形式で。

%% トリプルクオート (OTP 27)
Greeting = """
   Hello, World!
   Multi-line, no escaping needed.
   """,

%% シジル形式 (~b は binary)
Name = <<"Alice">>,
Greeting2 = ~b"Hello, #{Name}!".
%% => <<"Hello, Alice!">>

~b シジルで補間ありのバイナリ文字列、~B で補間なしのバイナリ。Elixir の ~s~S に近い設計。

現実: Erlang ユーザーは 30 年間 io_lib:format("Hello, ~p!", [Name]) を書いてきた。これからは ~b"Hello, #{Name}!" で済む。コードがはるかに読みやすくなる。

2-2. set_node_lookup_node / ノード探索の改善

分散 Erlang クラスタのノード探索は EPMD (Erlang Port Mapper Daemon) に依存していた。OTP 27 では、EPMD を迂回してノード名を直接登録できるコールバック API を正式化した。

2-3. persistent_term の改善 — 高速な読み出し

persistent_term はほぼ変わらないグローバル定数を高速に読むための、ETS のいとこである。書き込みは非常に重い(システム全体の GC を誘発)が、読み出しはほぼゼロコスト。

OTP 27 は内部実装を整理し、メモリ使用量と書き込み時の GC コストを削減した。設定値・鍵・ルーティングテーブルのような「ほぼ永続」データに、ますます使いやすくなった。

%% 1 回書いて、数億回読む
persistent_term:put({config, max_connections}, 100000),

%% ホットパスでほぼ無料
Max = persistent_term:get({config, max_connections}).

2-4. JIT 改善とコンパイラの診断

OTP 27 への移行チェックリスト

□ Rebar3 / Mix を OTP 27 互換バージョンに更新
□ Dialyzer を再実行(型システムが微妙に変化)
□ EPMD 代替コールバックを使うなら net_kernel 設定を確認
□ トリプルクオート文字列は IDE 対応を確認 (Erlang LS, ElixirLS)
□ 依存ライブラリの OTP 27 互換性を確認(大半は OK)

第 3 章 · OTP 28 プレビュー — 次に来るもの

2026 年 5 月現在、OTP 28 は release candidate 段階。正式リリースは 2026 年夏目標。主な変化。

3-1. JIT のさらなる最適化

3-2. set / map の標準ライブラリ拡張

%% OTP 28 で追加予定の maps 関数
maps:groups_from_list(fun(X) -> X rem 2 end, [1,2,3,4,5]).
%% => #{0 => [4,2], 1 => [5,3,1]}

%% set モジュールにも同様の便利関数

3-3. ssl スタックの現代化 — TLS 1.3 の完成

3-4. logger と telemetry の統合強化

3-5. 分散モニタリングの改善

まとめ: OTP 28 は革命ではない。磨き(polish) である。30 年ものの言語が毎年どう改善され続けるか、その良い例。


第 4 章 · Cowboy 3 — BEAM の標準 HTTP サーバ

Cowboy は Loïc Hoguin が作った小さく速い Erlang HTTP サーバ。Plug、Phoenix、RabbitMQ Management UI、ほぼすべての Erlang/Elixir ウェブスタックの既定 HTTP サーバ。

2024 年末に Cowboy 3 がリリースされた。中核の変化。

4-1. HTTP/2 の完成度

4-2. WebSocket の安定化

4-3. HTTP/3 — 実験的サポート

4-4. シンプルな Cowboy ハンドラ例

%% rebar.config に cowboy 依存を追加した上で

-module(hello_handler).
-export([init/2]).

init(Req0, State) ->
    Req = cowboy_req:reply(200,
        #{<<"content-type">> => <<"text/plain">>},
        <<"Hello from Cowboy 3!">>,
        Req0),
    {ok, Req, State}.

%% ルータに登録
start() ->
    Dispatch = cowboy_router:compile([
        {'_', [{"/", hello_handler, []}]}
    ]),
    {ok, _} = cowboy:start_clear(my_http_listener,
        [{port, 8080}],
        #{env => #{dispatch => Dispatch}}).

Cowboy を使う代表的なシステム


第 5 章 · Bandit — 純 Elixir で書き直された HTTP サーバ

Cowboy は Erlang で書かれている。Plug/Phoenix は Elixir で書かれている。両者をつなぐアダプタ (Plug.Cowboy) は常に存在したが、「Elixir スタック全体を Elixir で書きたい」という声があった。

Bandit (2022 年開始、Mat Trudel 主導)がその答え。

5-1. Bandit が狙ったもの

Cowboy:   Erlang  -> Elixir アダプタ (Plug.Cowboy) -> Plug/Phoenix
Bandit:   Elixir  ->                                -> Plug/Phoenix

5-2. Phoenix との統合

Phoenix 1.7 以降、Bandit を Plug.Cowboy のドロップイン代替として使える。

# config/config.exs
config :my_app, MyAppWeb.Endpoint,
  adapter: Bandit.PhoenixAdapter,
  http: [port: 4000]

これ 1 行で済む。Phoenix LiveView、channels、controllers すべてそのまま動く。

5-3. Bandit vs Cowboy — 2026 年比較

                      Cowboy 3            Bandit
ホスト言語            Erlang              Elixir
HTTP/1.1              本番運用済み         本番運用済み
HTTP/2                RFC 9113            RFC 9113
HTTP/3                実験的              まだなし
WebSocket             あり                あり
Plug 統合             アダプタ経由         ネイティブ
運用実績              10 年以上            3〜4 年
本番推奨              保守的なら ✓       新規 Phoenix なら ✓

5-4. どちらを選ぶか


第 6 章 · Khepri — RabbitMQ チームが作った Mnesia 後継

Mnesia は 1990 年代の Erlang の分散 DBMS。メモリ・ディスクハイブリッド、トランザクション、ETS 互換のインターフェイス。しかし netsplit (ネットワーク分断) 時の挙動が古くから弱点 として知られていた — 分断が起きると両側が生き残り、データが分かれ、再合流には手動介入が必要だった。

RabbitMQ チーム(Pivotal → VMware → Broadcom)がこの問題に正面から取り組んで作ったのが Khepri である。

6-1. Khepri の核心アイデア

「Mnesia を置き換える、ただし Raft 合意 をその下に敷く。」

6-2. Khepri のデータモデル

%% パスベースのツリー構造
ok = khepri:put([app, config, max_users], 1000),
{ok, 1000} = khepri:get([app, config, max_users]),

%% ワイルドカードクエリ
{ok, Map} = khepri:get_many([app, config, ?KHEPRI_WILDCARD_STAR]).

Zookeeper の znode、etcd のキーツリーに非常に近い設計。

6-3. RabbitMQ での採用

6-4. 自分のシステムで Khepri を使う

%% rebar.config に khepri を追加
{deps, [
    {khepri, "0.14.0"}
]}.

%% 起動
{ok, _} = khepri:start(),

%% トランザクション
khepri:transaction(fun() ->
    khepri_tx:put([users, alice], #{role => admin}),
    khepri_tx:put([users, bob], #{role => user})
end).

結論: Khepri は Mnesia を「静かに」置き換えつつある。新規の分散 BEAM システムでメタデータストアを選ぶとき、Khepri はますます合理的な選択になっている。


第 7 章 · Mnesia / partisan — 分散データと分散通信

7-1. Mnesia — まだ生きている

Khepri が登場したからといって Mnesia が消えたわけではない。2026 年でも:

指針:

7-2. partisan — 分散 Erlang そのものへの挑戦

既定の分散 Erlang (net_kernel) はフルメッシュトポロジを前提とする。すべてのノードがすべてのノードと直接接続。ノード数が 100 を超え始めるとメッセージ爆発と head-of-line blocking の問題が出てくる。

partisan (Christopher Meiklejohn ほか)がこれを再設計した。

distributed Erlang:  N ノード -> N*(N-1)/2 接続(フルメッシュ)
partisan:            複数のトポロジオプション
                     - フルメッシュ
                     - hyparview (P2P オーバレイ)
                     - クライアント・サーバ
                     - PG2 ベースの静的グループ

中核アイデア:

  1. マルチチャンネル — ノードペアの間に複数の TCP 接続。小さいメッセージが大きいメッセージで詰まらない。
  2. モノリシック vs P2P — トポロジを選べる。
  3. 後方互換gen_server インターフェイスをそのまま使え、内部だけ差し替え。

2026 年現在の partisan は:


第 8 章 · Nerves — 組み込み Erlang/Elixir

Nerves は Frank Hunleth 主導の組み込みフレームワーク。中核アイデア:

「Linux の上で BEAM だけを動かす。ユーザランド全部が Elixir/Erlang。」

8-1. Nerves が狙ったもの

8-2. 典型的な Nerves プロジェクト構成

# 新規 Nerves プロジェクト作成 (Raspberry Pi 4 ターゲット)
mix nerves.new my_iot_device --target rpi4

cd my_iot_device

# ファームウェアビルド
MIX_TARGET=rpi4 mix deps.get
MIX_TARGET=rpi4 mix firmware

# SD カードに焼く
MIX_TARGET=rpi4 mix firmware.burn

ファームウェアの中にはブートローダ、Linux カーネル、BEAM、そして Elixir アプリケーションが入っている。ユーザランドにはほぼ他に何もない。

8-3. 実例

8-4. NervesHub — OTA フリート管理

Nerves チームが作った NervesHub は、ファームウェア更新の中央管理システム。デバイス艦隊全体に段階的ロールアウトができる。

ポイント: Nerves は「組み込みも BEAM の supervisor の中で動かせば死なない」という仮説を実証するプロジェクト。


第 9 章 · gleam — 静的型付け BEAM 言語

gleam (Louis Pilfold 作、2016 年開始)は BEAM の上で動く 静的型付け 関数型言語である。2024 年にシード調達と 1.0 リリースを経て、本格的に注目を集めた。

9-1. gleam が提示するもの

import gleam/io
import gleam/list

pub fn main() {
  let numbers = [1, 2, 3, 4, 5]
  let doubled = list.map(numbers, fn(n) { n * 2 })
  io.debug(doubled)
}

9-2. なぜ静的型を BEAM に持ち込んだか

9-3. 簡単な OTP スタイルのアクター (gleam_otp)

import gleam/erlang/process
import gleam/otp/actor

pub fn main() {
  let assert Ok(subject) = actor.start(0, handle_message)
  process.send(subject, Increment)
  process.send(subject, Increment)
  // 二度インクリメント
}

pub type Message {
  Increment
  GetCount(reply_to: process.Subject(Int))
}

fn handle_message(message: Message, count: Int) -> actor.Next(Message, Int) {
  case message {
    Increment -> actor.continue(count + 1)
    GetCount(reply_to) -> {
      process.send(reply_to, count)
      actor.continue(count)
    }
  }
}

型のある OTP。プロセスが受け取れるメッセージの種類がコンパイル時に検証される。

9-4. gleam 1.0 以降の動き

9-5. gleam を選ぶべきとき


第 10 章 · Lustre — gleam のウェブフレームワーク

Lustre は Hayleigh Thompson が作った gleam のフロントエンドフレームワーク。Elm に強くインスパイアされた The Elm Architecture (TEA) パターン。

10-1. Lustre のモデル

        ┌─────────┐     Msg     ┌─────────┐
        │  View   │ ───────────>│ Update  │
        │ (HTML)  │             │ (モデル  │
        └─────────┘ <────────│  │  変更)  │
            ▲       Model       └─────────┘
            └──── ユーザー操作 ────┐
                            (ブラウザ)

10-2. シンプルなカウンタ (Lustre)

import lustre
import lustre/element/html.{button, div, text}
import lustre/event

pub fn main() {
  let app = lustre.simple(init, update, view)
  let assert Ok(_) = lustre.start(app, "#app", Nil)
}

fn init(_) {
  0
}

pub type Msg {
  Incr
  Decr
}

fn update(model: Int, msg: Msg) -> Int {
  case msg {
    Incr -> model + 1
    Decr -> model - 1
  }
}

fn view(model: Int) {
  div([], [
    button([event.on_click(Decr)], [text("-")]),
    text(int.to_string(model)),
    button([event.on_click(Incr)], [text("+")]),
  ])
}

10-3. Lustre の二つのモード

  1. クライアントサイド — gleam を JavaScript にコンパイルしてブラウザで実行。
  2. サーバコンポーネント — Phoenix LiveView スタイルで、サーバが状態を持ち、ブラウザは薄いクライアント。

サーバコンポーネントモードは LiveView に近いが、gleam の型安全性が持ち込まれる点で差別化される。

10-4. 2026 年の位置付け


第 11 章 · AtomVM — ESP32 で Erlang を走らせる

AtomVM (Davide Bettio ほか)は BEAM のバイトコードをマイコンで実行する VM である。

11-1. AtomVM が狙う場所

これらのボードは Linux を載せるには小さすぎる(普通は数百 KB〜数 MB の RAM)。Nerves は来られないが、AtomVM は来られる。

11-2. どう動くか

11-3. ESP32 での "Hello, Erlang"

-module(blink).
-export([start/0]).

start() ->
    Pin = 2,
    gpio:set_pin_mode(Pin, output),
    loop(Pin, high).

loop(Pin, State) ->
    gpio:digital_write(Pin, State),
    timer:sleep(500),
    NextState = case State of
        high -> low;
        low -> high
    end,
    loop(Pin, NextState).
# コンパイル後 ESP32 に焼く(概略)
erlc blink.erl
atomvm_packbeam blink.avm blink.beam
esptool.py write_flash 0x250000 blink.avm

LED 点滅のような入門例から始めて、BLE ベースの IoT デバイス、小さなメッセージゲートウェイまで作れる。

11-4. AtomVM と Nerves の比較

            AtomVM                       Nerves
ターゲット   MCU (ESP32, STM32)          SBC (Pi, BeagleBone)
RAM          数百 KB                     数 GB も可能
OS           なし (ベアメタル/FreeRTOS)  Linux
BEAM         AtomVM (subset)             正式な OTP
ユースケース センサノード、BLE デバイス  エッジゲートウェイ

最小ノードは AtomVM、それを集約するハブは Nerves、クラウドバックエンドは正式な OTP — そういう構図が成立する。

11-5. 2026 年現在


第 12 章 · RabbitMQ — Erlang の代表選手

RabbitMQ は別記事で取り上げているので、ここでは簡潔に。重要なのは この会社が Erlang を主流に押し上げた最大の貢献者 であること。

12-1. RabbitMQ が Erlang を選んだ理由

12-2. 2026 年の RabbitMQ

12-3. Erlang エコシステムへの影響


第 13 章 · 本番事例 — WhatsApp / Klarna / Discord / Riot / Cisco / Akamai

BEAM を真剣に使っている会社の短いケーススタディ。

13-1. WhatsApp — Erlang スケール伝説

13-2. Klarna — 金融スケールの Erlang

13-3. Discord — Erlang/Elixir ハイブリッド

13-4. Riot Games — Erlang 製チャット

13-5. Cisco — XMPP / 通信インフラ

13-6. Akamai — DNS の一部

ケーススタディの共通点

CPU バウンドではなく、同時実行性バウンド が本質の会社たち。


第 14 章 · 韓国・日本 — 東アジアの BEAM

西洋圏では BEAM がよく知られているが、東アジアでの採用はどう見えるか。

14-1. 韓国 — カカオ、通信会社、一部スタートアップ

現実: 韓国で BEAM は主流ではない。しかしメッセージング・リアルタイムが本質の会社では、静かに使われている。

14-2. 日本 — ピクシブ、NTT、通信インフラ

14-3. 東アジアで BEAM 採用が遅く見える理由


第 15 章 · 誰が BEAM を選ぶべきか — 意思決定ガイド

最後に 2026 年時点で「このプロジェクトに BEAM は合うか?」を判断する実用ガイド。

15-1. BEAM が強い領域

15-2. BEAM が弱い領域

15-3. 言語選択 — Erlang vs Elixir vs gleam

              Erlang              Elixir              gleam
型             動的                動的 (dialyzer)     静的
文法           Prolog 風           Ruby 風             Rust / Elm 風
エコシステム   古い、安定           最も活発            急成長
ツール         rebar3              mix (優れる)        gleam (簡潔)
主な用途       既存システム・OTP   新規 Web・Phoenix   新規型安全
学習曲線       文法ゆえに急        やわらかい           関数型経験者は速い

推奨:

15-4. HTTP サーバ選択

15-5. 分散データ選択

15-6. 組み込み選択


第 16 章 · 結び — BEAM は消えない

40 年にわたり、BEAM は通信会社の秘密兵器から始まり、インターネットのメッセージングインフラの背骨となった。2026 年の BEAM は:

BEAM の約束は変わらない — 「死なないシステム」。 30 年前に電話交換機が必要としたものは、2026 年の LLM 推論ゲートウェイ、メッセージキュー、IoT バックエンド、リアルタイム協業ツールにも同じく必要だ。

もしあなたのシステムが 「多数の接続を同時に維持し、絶対に死んではいけない」 種類のものなら、BEAM を真剣に検討する価値がある。メッセージングでも、決済でも、IoT でも、チャットでも。

BEAM は 30 年後にも、たぶん 50 年後にも、誰かのバックエンドで静かに動いているはずだ。


参考 / References

コメント

まだコメントはありません。

ログインするとコメントできます