箱庭PDUアーキテクチャ(その5)


箱庭PDUアーキテクチャの解説シリーズ、今回は一度立ち止まって、
これまでの解説内容を俯瞰し、丁寧にサマリーしようと、筆を取ることにしました。

前回(その4)について、「少し難しかった」という感想もいただきました。
これはもっともで、いきなり「ブリッジ」や「転送ポリシー」といった言葉が出てくると、
全体像の絵がない状態では消化不良になりやすいからです。
(すみません、ぶっ飛ばして書きました。ごめん、ごめん…)

そこで今回は、シリーズ(その1〜その4)で扱ってきたポイントを、次の観点から整理します。

  • 従来の箱庭は、そもそもどんな実装・構成だったの?
  • その構成のどこに課題(違和感)を感じていたの?
  • その結果、どこを“整理して切り分けたい”と思ったの?

このあたりのサマリーを挟むことで、次回以降(その6)で予定している 箱庭RPC の話も、
唐突な新要素ではなく「これまでの流れの延長」として続けられる状態にしたいと思います。

従来の箱庭は、そもそもどんな実装・構成だったの?

まず、これが従来の構成です。

一番下に 箱庭コア機能 があり、箱庭アセット間の通信や時刻同期を、共有メモリ(mmap) を通して実現しています。

この構成は、実はとても重要なポイントです。
一般的な分散フレームワークでは、同一パソコン内であっても TCP / UDP などのソケット通信API(システムコール)を用いてコンポーネント間通信を行います。

ぼくが、新入社員として入社した時、当時の技術部長に、
「システムコールは重い!」
って教わって、実際に、性能計測プログラムを書いて体感したのを今でも思い出します。しみじみ。

まー、そんなわけで、当然ながら OS の介在が発生するため、通信頻度が高くなると、そのオーバーヘッドは無視できないものになります。

箱庭では、この問題を避けるため、同一ノード内のアセット間通信は共有メモリを前提とした構成を採用してきました。

いわゆる、ゼロコピー[1]というやつです。

ここで言う「ゼロコピー」は、単にポインタを共有するという意味ではありません。 
「データの一貫性を保証した上で、CPUやOSによる無駄なコピーを発生させない」
という設計上の考え方です。

mmapで実現された共有メモリ領域は各プロセスのアドレス空間に直接マッピングされるため、
データアクセス時にシステムコールが発生せず、
カーネル空間とユーザー空間間でのデータコピーも不要になります。
この結果、同一ノード内においては、
コピー回数を極小化したゼロコピー指向の通信[2]が実現できます。

[1] “Zero-copy”, Wikipedia, https://en.wikipedia.org/wiki/Zero-copy 
[2] D. Stancevic, “Zero Copy I: User-Mode Perspective”, Linux Journal, 2003 https://www.linuxjournal.com/article/6345

その構成のどこに課題(違和感)を感じていたの?

本来、箱庭PDUは「どんな通信方式でやり取りされるか」とは独立した、
純粋なデータの単位であるべきだと考えていました。

しかし、従来の構成では、
PDUでの通信は基本的に共有メモリベースで行い、
外部のパソコンと接続する場合には、
箱庭ブリッジというコンポーネントを用意して、
そこでソケット通信(TCP / UDP / WebSocket / Zenoh / ROS など)を行う、
という形になっていました。

WebSocket であれ Zenoh であれ ROS であれ、
最終的にはユーザランドのプログラムはソケット通信を行います。

つまり、
「どの通信方式を使うか」 が、
PDUそのものではなく、構成や接続先によって
暗黙的に決まってしまっていた、ということです。

これって、なんか違うよね、という違和感でした。わかります?

その結果、どこを“整理して切り分けたい”と思ったの?

こうした違和感もあり、「箱庭PDUアーキテクチャ(その1)」では、
箱庭の分散シミュレーションの枠組み自体を、もう一度見直す必要がある、
という話をしました。

正直なところ、
「このまま継ぎ足していくのは、なんか違うな」
「ここで一回、ちゃんと整理し直さないとダメだな」
という感覚が強くなってきた、というのが本音です。

そこで、
通信方式や接続形態に引きずられていた構成を一度リセットし、
・PDUとは何か
・通信方式はどこで選ばれるべきか
・その責務をどこで切り分けるのか
を、改めて整理し直そう、という判断をしました。

いわば、「もう一回やり直そう」という宣言でした。

そもそも箱庭PDUとは?

そして、「箱庭PDUアーキテクチャ(その2)」では、
「そもそも箱庭PDUってなんだっけ?どういう位置付け?他と何が違うの?」
をあらわに説明しようとしました。

大事なことは何度でも言います。

箱庭PDUでは、次の要素を意識的に分離しています。

  • データ定義
  • データ変換
  • 通信プロトコル

この分離によって、PDUは特定の通信方式やフレームワークに縛られることなく、
「意味を持ったデータ」そのものとして扱えるようになります。

結果として、同じデータ定義を、
共有メモリ、TCP / UDP、WebSocket、Zenoh、ROS など、
さまざまな環境・通信方式で使い回すことができます。

これが一番やりたいこと、「理想」です。

箱庭PDUエンドポイント

こうした理想――
「PDUは通信方式から独立した、純粋なデータの単位である」
という考え方を、

箱庭PDUアーキテクチャ(その3)」で、
ようやく設計・実装として表現できるようになりました

これにより、箱庭PDUエンドポイントは、
箱庭アセットにとってかけがえのない存在になりました。

箱庭アセットは、PDUという抽象化されたデータを扱う際に、
それをどの通信プロトコルで送るのかを、一切意識する必要がなくなったのです。

さらに、その通信プロトコルは、
JSON ファイルで宣言的に記述できます。

つまり、
「構成をコードではなくデータ(コンフィグファイル)として扱える」ようになった、ということです。

そして――
これは、AI にとっても非常に相性が良いのです。

AI に、毎回コードを書き換え、リコンパイルし、
プログラムを実行させるのって、最悪ですよ…。
(コードミスとかあったら動きませんし、コードがどんどん複雑になるから…)。

AI にとって嬉しいのは、
設定ファイルの意味を教えてあげること。
そして、与えられた目的に応じて、
設定を自由に変更し、リコンパイルなしに、そのまま実行できること
なのではないでしょうか。

箱庭PDUブリッジ

これまで、箱庭が外部のパソコンやプログラムと通信するには、
共有メモリは使えませんから、
箱庭ブリッジを使ってもらっていました。

でも――
箱庭ブリッジの役割って、本当にそれだったのでしょうか?

外部と通信すること自体は、
それは 箱庭PDUエンドポイントの役割 ですよね。

では、箱庭ブリッジの本来の役割は何なのか。
そう考えたときに、行き着いた答えは、とてもシンプルでした。

それは、

「オーナーが書いた PDU を、別の人に伝えること」

ただそれだけです。
つまり、架け橋 です。

だから、箱庭ブリッジとは、
PDU のブリッジ なんですよ。

そういう意味を明確にするために、
このコンポーネントは
「箱庭ブリッジ」ではなく、「箱庭PDUブリッジ」
と呼ぶことにしました。

箱庭PDUアーキテクチャ(その4)」では、
少し過去の因縁を引きずった書き方になってしまい、
申し訳ありませんでした。

当時は、Zenoh を中心とした箱庭ブリッジの在り方に、
自分自身が違和感を感じており、
そのおもいが、そのまま文章に出てしまっていました。

ただ、今回あらためて整理してみて、
その違和感の正体は
「通信方式が前面に出てしまっていたこと」
だったのだと、はっきり言語化できた気がしています

架け橋と箱庭PDUブリッジを再定義した時に見えてきた景色はこうでした。

  • PDU の転送先は、複数あってもよい(fan-out)
  • PDU の転送先は箱庭PDUエンドポイントであり、通信方式はそれに従う
    (つまり、エンドポイントを切り替えることが、通信方式の切り替えになる)
  • PDU を転送するタイミングや周期は、選択できた方が良い

これまで箱庭アセットは、
「PDU を書く」「PDU を読む」
という I/O の視点だけを持っていました。

しかし、その I/O の“間”に箱庭PDUブリッジを置くことで、
アセットを一切変更せずに、通信頻度を制御できる
ということに気づきました。

設定を変えるのは、ブリッジだけで良いのです。

さらに見えてきた可能性(故障注入)

さらに言えば、

  • 通信途絶のタイミング制御
  • 異常データの注入

といったことも、やろうと思えばできる、というところまで見えてきました。

故障注入が「設定だけ」でできる構造

さらなる気づきは、
故障注入をコンフィグだけで実現できるという点です。

やり方は、とてもシンプルです。

  1. 書き出し側のエンドポイントを、故障注入用のエンドポイントに差し替える
    (ここはコンフィグ変更だけ。アセット側には一切影響なし)
  2. 受け手側で、その PDU に対して故障注入を行う
  3. 書き出し先を、本来送りたいエンドポイントに向ける

アセットは何も知りません。
PDU を書いているだけです。

これはつまり、

  • アセットは純粋に振る舞いを書く
  • ブリッジが世界の不確かさを引き受ける

という役割分担が、
構成として初めてはっきりした、ということだと思っています。

最後に。

ここ最近、

ごめん、
 箱庭PDUエンドポイント最高!
 箱庭PDUブリッジ、すごすぎ!!

って思っています。

なぜか。

箱庭PDUエンドポイントと箱庭PDUブリッジは、
関心の分離(Separation of Concerns) の教科書的な設計なんです。

  • アセットは、純粋に振る舞いを書く
  • ブリッジは、世界の不確かさを引き受ける

これは単なる技術的な分離ではなくて、哲学的な役割分担とも言えます。

  • アセット:理想世界での振る舞い(決定論的)
  • ブリッジ:現実世界の不確かさ(確率論的)

この分離によって、

  • 故障注入
  • 通信遅延のシミュレーション
  • ネットワーク分断のテスト

が、可能になりました。
 箱庭アセットのコードを一切変更することなく。
です。

AIとの相性についての洞察

AI にとって嬉しいのは、

  • 設定ファイルの意味を教えてあげること
  • 与えられた目的に応じて設定を自由に変更できること
  • リコンパイルなしに、そのまま実行できること

ではないでしょうか。

2026年現在、LLM ベースの AI エージェントが広く使われていますが、

  • 宣言的な設定ファイルは、AI が理解・生成しやすい
  • コンフィグ駆動は、AI が試行錯誤しやすい
  • 即座の実行は、AI のフィードバックループを高速化する

箱庭PDUアーキテクチャは、
意図せずして AI-Friendly な設計になっていた
ということに気づきましたのです。

……やばい。
箱庭すごすぎ。
無意識で作ってたのに。
今の時代に、めちゃくちゃ合ってるやん。

つづく。


コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

PAGE TOP