LabHub

ブログ

ブラウザの外のWebAssembly

한국어English日本語中文

はじめに — ブラウザは始まりにすぎなかった

WebAssembly(略してWASM)を初めて聞くと、たいてい「ブラウザでC++を動かす技術」くらいに理解します。間違いではありません。WASMは実際にブラウザで生まれ、JavaScriptには荷が重い重い計算をウェブで可能にするために作られました。

しかしWASMの本当の野心はブラウザの外にあります。よく考えてみると、WASMがブラウザで解決した問題(安全に隔離され、どんな言語からもコンパイルでき、近ネイティブ速度で動く移植可能なバイナリ)は、ブラウザとは何の関係もない性質です。これらの性質は、サーバーでも、エッジでも、プラグインシステムでも同じように魅力的です。

この記事は、ブラウザを離れたWebAssemblyを扱います。WASMがシステムと対話するために作ったWASIというインターフェース、エッジとサーバーレスでなぜWASMがコンテナを脅かすのか、プラグインシステムでなぜWASMが正解になりつつあるのか、そしてコンポーネントモデルがこのすべてをどう結び付けるのかを見ます。WASMがどうやって近ネイティブ速度を出すのか、その原理をブラウザで直接試したいならWASM原理ラボが良い出発点で、WAT(WebAssemblyテキスト)を手で書いてバイナリにコンパイルしてみたいならWebAssemblyスタジオで実験できます。

三つの性質 — なぜWASMが汎用ランタイムなのか

WASMがブラウザを越えて広がる根本的な理由は、三つの性質にあります。この三つはもともとブラウザのために設計されましたが、実は はるかに広い場所で通用する普遍的な美点でした。

この三つの性質を並べてみると、これがなぜ強力な組み合わせなのかが見えてきます。コンテナは隔離と移植性を与えますが、重くて起動が遅いです。ネイティブバイナリは速いですが隔離が弱くアーキテクチャに縛られます。インタプリタ言語は移植性が良いですが遅いです。WASMはこの三つの良い点(速い、安全、移植可能)を一つの封筒に入れようとする試みです。この組み合わせが効く場所がブラウザだけではない、というのが核心です。

WASI — WASMがシステムと対話する方法

ここで根本的な問題が一つあります。WASMモジュールはデフォルトでは何もできません。ファイルを読むことも、ネットワークに接続することも、時計を見ることもできません。ブラウザではこれは問題になりません。JavaScriptが必要な機能をすべて渡してくれるからです。ところがブラウザの外では? JavaScriptのないサーバーでWASMがファイル一つ読むのに、何に頼ればいいのでしょうか。

この空白を埋めるのがWASI(WebAssembly System Interface)です。WASIは、WASMモジュールがシステム資源にアクセスするための標準化されたインターフェース、いわばPOSIXふうのシステムコール規約です。ファイルを開く、読む、書く、時計を読む、乱数を得るといった基本機能を、WASMモジュールが呼び出せる標準関数として定義します。

核心は、WASIが能力ベースのセキュリティ(capability-based security)モデルに従う点です。従来のプログラムは、実行された瞬間、そのユーザーがアクセスできるすべてのファイルにアクセスできます。WASIモジュールは違います。デフォルトではどのファイルにもアクセスできず、ホストが明示的に渡したディレクトリやファイルハンドルだけを使えます。

  従来のプロセス:
    実行 = 「このユーザーの持つすべての権限をそのまま継承」
    (プログラムが好き放題にファイルシステム全体を漁れる)

  WASIモジュール:
    実行 = 「何の権限もなく開始」
    ホストが渡したものだけ使用可能
    (例: 「この一つのディレクトリだけ読め」— 残りは存在すらしない)

このモデルの含意は大きいです。WASMモジュールにちょうど必要な能力だけを与え、残りをまったく見えなくできます。信頼できないコードを動かすとき、「このプログラムが誤ってか悪意でか何に触れられるか」という心配が根本的に減ります。隔離が「デフォルト遮断、明示的に許可」という安全な方向にひっくり返っているからです。

WASIは進化し続けています。初期のWASIがファイルや標準入出力といった基本に集中していたのに対し、以降のバージョンはネットワーキングや非同期I/Oといったより豊かな機能へ範囲を広げています。この進化の方向が、後で扱うコンポーネントモデルと噛み合います。

エッジとサーバーレス — コンテナを脅かす

WASMがブラウザの外で最も熱く使われている場所が、エッジコンピューティングとサーバーレスです。FastlyのCompute、Cloudflare WorkersといったプラットフォームがWASMを実行単位として採用したことで、「リクエストをどう処理するか」の構図が変わりつつあります。

なぜよりによってWASMなのでしょうか。サーバーレスとエッジの核心的な課題はコールドスタートです。リクエストが来たとき、コードを実行する環境をどれだけ速く立ち上げられるかが鍵です。ここでコンテナとWASMの違いが際立ちます。

この違いが生む結果は大きいです。コールドスタートが事実上消えると、リクエストごとに新しいインスタンスを立ち上げることが負担でなくなります。すると、リクエストをユーザーに最も近いエッジノードで、必要なときだけ一瞬で立ち上げて処理し捨てるモデルが現実的になります。各エッジノードに重いコンテナオーケストレーションを入れる必要なく、軽量なWASMランタイム一つで多数のテナントのコードを安全に隔離して動かせます。

密度(density)の面も重要です。WASMインスタンスはコンテナよりはるかに軽いので、同じハードウェアではるかに多くのインスタンスを同時に動かせます。エッジのように資源が限られた環境で、この密度はそのまま経済性です。一つのプロセスの中で数千の隔離されたWASMインスタンスを動かすことは、数千のコンテナを動かすことよりはるかに安価です。

もちろんトレードオフもあります。WASM/WASI環境は完全なLinuxではないので、既存のコンテナイメージをそのまま移せません。アプリケーションがWASIのまだ対応していないシステム機能に依存すると行き詰まります。つまりエッジWASMは「軽くて速いが制限された」環境であり、完全なOSが必要なワークロードには依然としてコンテナが合います。

プラグインシステム — WASMが正解になる場所

WASMが静かに、しかし決定的に地歩を固めているもう一つの領域がプラグインシステムです。あるアプリケーションに第三者が作ったコードを安全に組み込みたいとき、WASMはほぼ理想的な答えになります。

プラグインの古いジレンマを考えてみましょう。プラグインは強力でこそ有用ですが、強力なほど危険です。ネイティブプラグイン(たとえば共有ライブラリ)はホストプロセスと同じアドレス空間で動くので、バグ一つがホスト全体を殺し、悪意あるプラグインが何でもできます。逆にプラグインを別プロセスに隔離すると安全ですが、遅く複雑になります。

WASMはこのジレンマを綺麗に解きます。プラグインをWASMモジュールにすれば、ホストと同じプロセスの中で速く動きながらサンドボックスで隔離されます。プラグインはホストが明示的に渡した関数だけを呼べ、ホストのメモリを好き放題に触れません。おまけにどんな言語でもプラグインを書けるので、プラグイン開発者がホストと同じ言語を使う必要もありません。

実際の事例がこの方向を証明します。

これらの事例の共通点は、「信頼できない拡張コードを、ホストを脅かさずに、速く実行」する必要です。これがまさにWASMの三つの性質(速い・安全・言語非依存)が輝く地点です。プラグインシステムを新しく設計する人なら、今やWASMを真剣に候補に挙げる価値があります。

コンポーネントモデル — モジュールを越えて

ここまで話してきたWASMは、たいてい「モジュール」という単位でした。しかし純粋なWASMモジュールには実務で痛い限界があります。モジュール間で、あるいはモジュールとホストの間でやり取りできるのが、基本的に数値(整数と浮動小数点)だけだということです。文字列一つ、リスト一つ、構造体一つを渡そうとしても標準化された方法がなく、各自でメモリのポインタと長さをやり取りする低レベルの規約を手で合わせる必要がありました。

この問題を解くのがコンポーネントモデル(Component Model)です。コンポーネントモデルは、WASMモジュールの上に高レベルの型システムとインターフェース定義を乗せます。文字列、リスト、レコード、バリアントといった豊かな型をインターフェースのレベルで定義し、異なる言語で書かれたコンポーネントたちがこの型を通じて自然に通信できるようにします。

核心のアイデアを整理するとこうです。

コンポーネントモデルが重要な理由は、これがWASMを「ブラウザでC++を動かす技術」から「言語中立なソフトウェア組み立て規格」へ格上げするからです。先に見たWASIの最新の方向も、このコンポーネントモデルの上で定義されます。つまりシステムインターフェースさえコンポーネントインターフェースで表現され、プラットフォームが提供する能力とモジュールが要求する能力が同じ型言語で噛み合います。

なぜこれが汎用ランタイムなのか — 大きな絵

ここまでの断片を一つにまとめてみましょう。WASMは近ネイティブ速度で動き、言語に依存せず、強くサンドボックスされ、アーキテクチャに移植可能です。WASIがシステムアクセスを能力ベースで標準化し、コンポーネントモデルが言語間の組み立てを可能にします。この絵を遠くから見ると、見覚えのある何かが浮かんできます。まさに「汎用ランタイム」の輪郭です。

歴史的に私たちは「一度書いてどこでも動かす」という夢を何度も追いました。そのたびに代償がありました。移植性を得るために重いランタイムを入れたり、性能を諦めたり、特定の言語に閉じ込められたりしました。WASMが興味深いのは、これらの代償を同時に減らそうとする点です。

これがWASMがブラウザを越えてサーバー、エッジ、プラグイン、さらにはIoTまで広がる理由です。「安全に隔離された、速く移植可能なコード実行単位」という必要はどこにでもあり、WASMはその必要へのかなり良い答えだからです。

冷静な現実 — まだ残る課題

もちろん、WASMがすべてを征服したという話は誇張です。ブラウザの外のWASMには、まだ成熟途上の部分が多くあります。

これらの課題を総合すると、ブラウザの外のWASMは「潜在力は明確だが、まだ埋められている最中」の技術です。今日すぐにすべてのコンテナを置き換えることはできませんが、信頼できないコードを軽く隔離する必要のある特定の領域(エッジ関数、プラグイン、マルチテナント実行)では、すでに実戦で優位を見せています。

おわりに — ランタイムの再発明

WebAssemblyはブラウザで生まれましたが、それが本当に再発明しているのは「コードを安全に速く、どこでも実行する方法」そのものです。近ネイティブ速度、サンドボックス隔離、アーキテクチャ移植性という三つの性質は、ブラウザだけの必要ではなくコンピューティングのどこにでもある必要であり、WASMはその必要に一つの封筒で答えます。

WASIがシステムとの対話を能力ベースで標準化し、エッジとサーバーレスがコールドスタートの壁を崩し、プラグインシステムが信頼のジレンマを解き、コンポーネントモデルが言語の障壁を下げます。これらの断片が集まると、WASMは特定のプラットフォームの技術ではなく、プラットフォームを横断する汎用実行規格に近づきます。

もちろん、行く道は残っています。エコシステムは埋められている最中で、標準は固まっている最中で、完全なOSを置き換えもしません。しかし方向は明確です。次に「この信頼できないコードをどう安全に動かすか」「このロジックをどう複数の言語と複数の環境で再利用するか」を悩むことがあれば、ブラウザの外のWebAssemblyを候補リストに載せておいてください。そのリストでWASMが占める位置は、毎年広がっています。

参考資料

コメント

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

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