本セッションの登壇者
セッション動画
よろしくお願いします。ご紹介いただいたとおり、「V8 as a container on CDN Edge Worker」という強いテーマで発表させていただきたいと思います。
自分の自己紹介は、どうでもいいんですけどスプラトゥーン3がS+1になりました。それは置いておいて、この資料は「Edge Side Frontendという新領域」というタイトルで別の所に出した内容のフォーカスを変えて再構成したものになります。ほとんど新規で書いたものなので、前のを読んだ人もたぶんおもしろいと思います。

V8は”Dockerに続く新しいコンテナ抽象”か?
「V8 as a Container」というこの言葉は何かというと、今年前半に出た『JavaScript Containers』というライアン・ダール(Ryan Dahl)の記事があるんですけど、JavaScriptエンジンであるV8はLinux Dockerに続く新しいコンテナ抽象であるという主張です。

以下はこの記事のDeepL翻訳ですが、「JavaScriptは世界共通のスクリプト言語です。JavaScriptの普遍性のために、サーバを単純化する新しいコンテナのような抽象化が出現しています」「私はLinuxコンテナがなくなると主張しているわけではありません。その抽象化のレベルはつねに有用です。ただ、人々が書く”ビジネスロジック”の多くは、むしろ低レベル過ぎます。Webサイトを作るとき、systemdのコンフィギュレーションなどは定型的なものです」などの主張です。わからなくはありません。

また、「Webサービスの大部分は、Linuxコンテナではなく、JavaScriptコンテナの観点から考えることで、簡略化できるかもしれません」「Webは人間のためのものであり、実行環境がスクリプティング言語であることは理にかなっています」。ここで言うスクリプティング言語とは、CやRustなどのあたりの言語と対比している感じですね。

これについて皆さんどう思いますか? という話を今日はしたいと思います。
この後のEdge Workerの話につながっていくんですけれど、自分の意見としては、ライアン・ダールの意見はJSびいき過ぎて言語の中立性を欠いていると思います。普通はそういう印象を受けると思います。JSじゃなくてもたとえば、V8と作者の同じDartもV8 Isolateとほぼ同じモデルを持っていますし、他の言語もサンドボックス的なものは程度により持っています。が、現状に即した選択肢としてJavaScriptを中心に据えるのは妥当だと思っていて、V8というのはブラウザの一部として信頼できないユーザーコードを評価するものとして進化してきたよねという話です。余談ですけれど、OSレベルじゃなくてプログラミング言語のレイヤでセキュリティを担保しようというライアンのこのポリシーは、DenoのPermissionの仕組みという形で現われていると思います。

V8 IsolateオーケストレーションでVMコールドスタート解消
V8 Isolateの説明ですが、これはコード実行単位ごとのプロセスを分離する機構、分離する単位です。V8にはsnapshotというメモリの状態をシリアライズできる機構があって、これがエッジやブラウザで大事だったりするんですけど、実行環境はwindowやHTMLElementといったコードを組み立てたスナップショットを実行ごとにロードして流すという感じです。

V8 as a Containerというのは、サーバサイドでV8をコンテナとして使うということです。サーバで大量のV8 Isolateを生成しておいて、デプロイというのはつまりユーザー側のJSを配置することであり、プロセスの初期化というのはV8 Isolateとユーザーコードを評価することです。リクエストが来たら、Requestオブジェクトを作って、V8 Isolateコンテキストに引数としてコードを渡して実行するという感じです。すごく簡単に言うと、ブラウザで50個、100個といった大量のタブを開いて、それをサーバの実行単位としてやっているということですね。

これはつまり何かというと、Cloudflare Workersのアーキテクチャが図のようになっていて、V8 Isolatesがいっぱい並んでいます。これをV8 IsolatesオーケストレーションとCloudflareは言っています。

Workerがどう動いているのかというと、この記事によると数百、数千のIsolateを1つのランタイムで実行できて、V8自体がセキュリティサンドボックスになっている。このモデルによって、仮想マシンのコールドスタートが解消されているという話です。おおざっぱに言うと、コンテナを立ち上げるより、JavaScriptのプロセスを作る方が軽いという話ですね。

V8 Isolateのオーケストレーションをすると、パフォーマンス特性がCDN Edge Workerになるのだと思います。コンテナ抽象をJSのV8 Isolateに決め打ちすることで高速性を得た、その結果CDN Edge Workerの機能要件を満たしたから、普通のPaaSとしてやるよりCDN Edge Workerとしてやっていこうぜ! という話だと思っています。

実際、Cloudflare Workersのプライシングを見ると、無料プランと、バンドルプランという5ドル払うプランと、アンバウンドというバンドルプラン上のオプションがあります。お金を払えば払うほど制限が緩くなっていくんですけど、お金に関わらずデプロイできるJavaScriptは1MBまでなんですね。

これは先ほどのモデルなんですけれど、これ、プロセス1個につきメモリを割り振る量が128MBの決め打ちなんですね。この中で展開できるJavaScriptで、負荷がない現実的な範囲でやると1MBまでみたいな話になっているのではないかと思います。

実際にメモリをどう組み立てるかはコードしだいなんですけれど、そのあたりを考慮されて1MBまでになっているのではないかと思います。注意する点として、CPUタイムに非同期のアイドルタイムは含まないので、フェッチとかキャッシュを触っている時間とか、非同期でウェイトしている時間は含んでいません。なので、実際、V8で10 ms使うのはなかなか重い処理なので、フリープランの10msでも意外といけるという感じです。
こういう制約から考えるCDN Edge Workerの用途というと、よく使われるのはL7 Proxyですね。アプリケーションの前に挟んでキャッシュ制御するとか、既存のCDNに対するプラスアルファ(A/Bテストとか、カナリーリリースとか)です。それとは別に、もともと今までもL7 Proxyみたいなものができていましたが、Edge Workerだったらできることとしては、Node.js代替のサーバサイドスクリプティングがあります。制限を許容して、アプリケーション全部をエッジ上で実装するということも可能だと思います。たとえばnpmはCloudflare Workersで実装されています。別のパターンとして、Next.js、Remix、SvelteKit、Nuxtなどを、CloudflareのCDN Edge Workersにデプロイするアダプタもあります。

最適化か言語中立性か
別のパターンとしてWebAssemblyのサンドボックスでも同じことができるはずです。
Compute@Edgeは、同じようにサンドボックス化されたプロセスが事前コンパイルされた .wasmを実行しているというモデルで、C++/Rustをホスト言語としていることが多いです。

WebAssemblyのサンドボックスは、基本的に割り当てられたメモリを書き換えることしかできなくて、しかも実行ごとに外部メモリ境界のチェックが挟まるので、これによって安全ではあるけれども遅いという特徴があります。外部APIのバインディングの仕組みがあって、システムコールとしてWASIのスペックがあります。

このあたりは時間がないので紹介できませんが、割り当てたメモリをお互い触っているという処理です。ただwasm側からは割り当てられたメモリしか見えません。

WASIもwasi_snapshot_preview1のファイルディスクリプタライト(fd_write)を呼んでいるだけなので、ここの名前はもう、現在こういうプロポーザルに実装されてfd_writeと呼んでいるぐらいの意味しかなくて、実体は自分で好きに実装できます。

現状の課題としては、ビルドサイズが大き過ぎて、実はJSよりもオーバーヘッドが大きいことです。自前のGCを持たないのでGC付き言語はさらにビルドが跳ねたり、あと個人的には、システム開発ではないウェブアプリケーションのレベルでは、C++やRustはあまり向かないんじゃないかなと思っているところがあります。

まとめとしては、V8はWebアプリケーションのためのコンテナ抽象として捉えることができるのではないかという話です。
そういうふうに考えた場合、V8 IsolatesオーケストレーションでCDN Edge Workerみたいなことができるようになっています。WebAssemblyによるCDN Edge Workerは言語中立ですが、正直なところビルドサイズの面で実際、C++かRustしか選べないという話があります。ただ、どちらもランタイム決め打ちでプロセスを大量に確保して実行、というのは、V8でもWebAssemblyも一緒ですね。ここは結局変わらないので、最適化を取るか、言語中立性を取るかみたいな話だと思っています。

以上です。ありがとうございました。