ミクシィには、探究心溢れるエンジニアがたくさん在籍しています。
その探究心は業務で扱う技術にとどまらず、趣味で書いているプログラムだったり、個人的に研究している言語だったりと、自身の気になった技術への追求も留まることを知りません。
そこで、社内のエンジニアに“好きな技術”について、思う存分に語ってもらうシリーズを始めました。
ルールはこの通り。
- 業務で使っている技術でも、使われていない技術でもOK
- あくまでも個人的な見解で
- その技術のどこが面白いのか
- 愛を込めて語り尽くしてもらう
第4回目は、新規プロダクトを目下開発しているSREグループの神谷に、「WebAssembly」の魅力をたっぷり語ってもらいました。
2018年4月、株式会社ミクシィに新卒入社。モンスターストライクにてサーバーサイド、インフラの開発を経験したのち、現在は新規事業にてサーバーサイドのリードエンジニアを務める。Twitter @GentaKamitani
Webの技術でもないしアセンブリでもない?
──早速ですが、今アツい技術について教えてください!
今回話すのは「WebAssembly(以下Wasm)」についてです。生まれた背景はブラウザ用のJavaScript(以下JS)よりももっと早くコードを実行できる方法が欲しかった、らしいです。
──なるほど。ではWebの技術なのですね。
ただちょっとややこしいんですけど、WasmそのものはWebでもなければアセンブリでもないんです(笑)。Webブラウザ上で動かすということを一番の目的としているんですけど、Wasmの仕様そのものには、特にWebに関するものが入っていなくて。さらに、特定のアーキテクチャの機械語に強く対応しているわけではないのでアセンブリではないです。ちょっと謎な命名なんですけど、JSと対比してよりネイティブな実行形式に近い形っていう意味でのアセンブリなのかと思います。
──JSの上位互換ということですか…?
上位互換ではなく、JSと協調して動かせるWeb周辺の技術のうちの一つというシステムですね。Wasm自体は、計算しかできないんですね。例えば足し算引き算とか。そういった純粋な計算しかできないかわりに、それらをJSよりも速く実行できるように設計されています。
──メインの機能は計算のみ、と。
まず、その機能がメインとしてある、ということですね。それとは別に、Wasmを実行している外側の環境から機能をインポートしてきたり、その外側に対してエクスポートして提供する機能っていうのがあります。
──外側の環境、というのは?
色々ありますが、一番メインとして見られているのはブラウザですね。例えば、ブラウザ上でWasmを使うのであれば、まずJSを書きます。次に、書いたJSの中でWasmのファイルをダウンロードし、解釈して実行します。さらに、実行するWasmに対して、決められたインターフェースを通してブラウザやOS、アプリケーション等の機能を提供することもできます。
──なるほど。
すると、Wasm側は計算だけをしつつ、例えばちょっと画面に何か表示したい時に、JSから渡された関数をWasm側から読み取ったりとか。逆にWasmがその計算する関数をJS側に提供するなんてこともできます。例えば、ブラウザ上で物理演算を使ったゲームを動かしたいとか、機械学習とかを動かしたいとします。そういうJSでは遅いような、もっとCPUを使う処理を一部だけWasmに肩代わりしてもらって、残りの操作はJS側から行う。こういった形で、JSとWasmを連携してブラウザ上で実行することができるようになっています。
──でもそれは、JSと連携する場合の一例なんですね。
そうですね。それ以外でよく知られたユースケースとして、普通にサーバーサイド等のアプリケーションを書きたいというものがあります。このようなユースケースのために定義されている「外側の環境」に相当するものとしてWASIというものがありまして、これは例えばファイルの読み書きなどのOSが提供する機能をWASM側から利用するための統一的なインターフェースを定めています。
──その他にはどんなユースケースがあるんですか?
例えば、既にあるソフトウェアに機能を拡張したい場合ですね。例で言うとExcelのVBAとか。1個の完成されたソフトウェアがあって、ユーザーがカスタマイズできるスクリプタブルな部分を付けたりとか。そういった場面でもWasmが持ってる機能が有効で、Wasmはプラグインとしても使いやすい設計になっています。アプリケーション側はプラグインに対してWasmのimportという形で機能を提供し、プラグイン側は拡張機能をWasmのexportという形でアプリケーション側に提供することができます。Wasmが外の世界に対して副作用を起こすには、それを起こすための機能を外側がimportを通して提供する必要があります。逆に、それ以外の方法でWasmが外の世界に影響を及ぼす手段はありません。つまり、Wasmで書かれたコードは外側のアプリケーションがそう意図しない限り、勝手にファイルにアクセスしたり、TCPコネクションを開いたりすることは原則としてできないわけです。このような性質は、プラグインとして任意のコードを動かしたい、でも本当に何でもかんでもされたら困るというような場合においても有効だと思います。Wasmのそういった性質を鑑みると、将来いろんな部分でプラグインとして使われていくのかなと思っています。このような用途としてはLuaというスクリプト言語が有名で、例えばnginxやRedisなどがLuaによるスクリプティングをサポートしています。ゆくゆくはWasmがそういった分野で覇権をとっていく可能性も十分あるかなとは思っています。
──なるほど。LuaとWasmの大きな違いはどこにあるのでしょうか?
いい質問ですね(笑)。そもそも何が違うのかというと、Luaはプログラミング言語、それに対してWasmはコンパイルのターゲットとなる言語です。ということは、例えば、あるソフトウェアのプラグインを、Luaで書くとします。となると、まずLuaを勉強して書けるようにならないといけない。とはいえ、Luaよりも静的型検査がしっかりしている言語で書きたいとか、○○言語で書けたらいいのに、という状況もあったりします。Wasmはコンパイル先の対象となるバイトコードなので、そもそもコンパイラが必要。Goで書きたいと思ったらGoで書いて、Wasmにコンパイルして、それをプラグインとして加えればいい。RustでもC++でも実装する側が好きな言語で実装できる、というのが1つの特長ですね。ただ、これをやるには、コンパイルする側やプラグインを提供している側をつなぐ部分を書かないといけないので、それはそれで大変でもあります。とはいえ、そういうことが実現可能になったわけです。これがLuaとの大きな違いですね。もちろんGoやRustのコードをLuaにコンパイルするという手段も無くはないとは思いますが、最初からそういう用途を目指しているかどうかという部分は大きな違いです。
──目指している姿に違いがあると。
Wasmが目指しているのは、高速であること。そのためにはWasmで書かれたコードが高速に実行できる必要があるのはもちろんですが、それ以外の要件もあります。基本的に、Webブラウザは動的に1ページ1ページごとにスクリプトやHTMLを読み込みます。そのため、いくらWasmの実行自体が高速だとしても、Wasmで書かれたコードのダウンロードやパース、コンパイルに時間がかかってしまっていては意味が無くなってしまいます。そのため、Wasm自体の表現も小さくならないといけなかったり、パースやコンパイルがしやすいフォーマットでないといけなかったり等、追加の制約が発生します。
次が、ポータビリティ。CPUのアーキテクチャに非依存。これがどういうことかというと、Webサイトは今、WindowsやMacなどのPCやスマホからでも閲覧できますよね。なんならTVやゲーム端末からでも。しかしながら、それぞれCPUは違いますよね。CPUが違うため、機械語も違います。すると、こっちのPCでは動くけど、こっちのPCだと動かない、ということが起こってしまう。それと同じような感じで、OSも種類ごとに提供している機能が違ったり、提供する方法が違ったりします。そのため、同じCPU向けの機械語であっても、OSが違えば一般的には動かなくなってしまいます。それに対して、Wasmで書かれたプログラムはどんなCPUでも、どんなOSでも、その環境でWasmのVMがある限りは同じように動くことを意図して設計されています。
──非依存、というのはそういうことなんですね。
ブラウザ上の話に関して言うと、Wasmがどのブラウザでも同じように動くことを目標としているという点も重要です。Wasmは特定のブラウザ専用の拡張機能ではなく、Webの標準として仕様が定められています。そのため、最近のメジャーなブラウザであれば、種類を問わず同じようにWasmのプログラムを実行することができます。Chromeでは動くけど、Firefoxでは動かない…というのは望ましくないですよね?現状、そういうサイトっていっぱいありますが(笑)。
──確かに。
さらに、セキュアであること。通常ブラウザを開くと同時に、利用ユーザーの無意識のままプログラムが勝手に実行されてます。そこにもし悪意のあるコードが書いてあったとしたら……あとはわかりますよね(笑)。なので、一般にブラウザ内で動くJSはそれ以外のプログラムと比べてできることが大きく制限されており、サイト閲覧者のPCにあるファイルを許可なく読み書きしたり、スクリプトの配布元とは関係ないサイトに関する情報の取得やアクセスをしたりすることができない仕組みになっています。この制約によって、JSはサイト閲覧者の許可なく勝手に実行されても一般的に問題ないと考えられるだけの信頼性を担保しています。ここにWasmを加えることでこの信頼性が崩れてしまったら、とんでもないことになってしまいますよね?
もちろん、Wasmはこの点を問題なくクリアしています。先ほど説明したとおり、Wasm自体はただの計算しか行うことができず、外のファイルを勝手に書き換えたりといった副作用を起こすことはできません。また、ブラウザで動かす限りWasmがインポートできるものはJavaScriptで書けるもののみなので、結局WasmはJSにできる以上のことはできないということになります。このような性質によって、慎重に設計されたWebの信頼性を損なうこと無く、WebのエコシステムにWasmを加えることができるわけです。
──堅牢性ですね。
さらにもう一つ。重要な特徴として、Wasmはプログラミング言語というよりは、コンパイル先なんです。
──厳密にいうと、プログラミング言語ではない?
うーん、解釈が難しいところがありますが、少なくとも僕らがテキストとかでカリカリ書くことをメインで想定するものではなくて。例えば、GoとかCとかで書かれたコードをWasmにコンパイルして実行するような使い方を想定している、というと分かりやすいでしょうか。
一旦この辺がWasmの主要な特徴です。ここで重要な点としては、これらの個々の性質自体は特に真新しいものではないということ。似たような取り組みとしてはNaCl,PNaClやasm.jsなどが昔からあり、それぞれ今述べたような性質をある程度カバーしていました。Wasmの重要な部分は、それらを全部カバーする、ベンダー非依存な標準仕様であるという所です。これによって、ブラウザ、OS、CPUに依らずに、ネイティブと遜色ない速度のプログラムをブラウザ上で動かすということが可能になりました。そういう意味で、WasmはWebの世界に大きな変革をもたらしました。
──なるほど。ちょっとずつ分かってきました。
…ではこの先、どう使われる?
──身近なサービスにも使われる可能性がある?
現時点で、メジャーなブラウザはWasmをサポートしています。なので、今そのへんのWebサイトを開くだけでも、実は裏側でWasmが動いているという可能性は十分あると思います。例えば、だいぶ早いWasm導入例として、Google Earthとか。これも結構前の話ですけど(笑)。ブラウザで何が出来るかというと、今までブラウザで動かすには重すぎたものが動かせる。3Dだったり、動画だったり…。
例えば、Google Meetでは背景のぼかし機能やバーチャル背景機能を実装するために、Wasmが使われています。こういった機能は画像認識や機械学習の技術を用いて実装されることが多いんですが、こういった処理は多くの場合CPUを大量に消費します。そのため、一昔前まではブラウザ上でこういった処理を行うことはあまり実用的とは考えられていなかったと思います。しかし、Google Meetはこのような処理を実際に実現可能にしたわけです。これを実現可能にするにあたって、Wasmが与えた影響は大きいと思いますね。
その他にも、複雑な物理演算を伴うゲームなどもブラウザ上でプレイできるようになる可能性があります。もちろん現時点でハイエンドPCが必要なレベルのゲームがWasmを使うだけで簡単に誰でも遊べるようになるわけではないですが、ブラウザで誰でも遊ぶことができるゲームの種類や、表現の手段の幅が広がる可能性があります。
また、FFmpegやSQLite等を筆頭に、有名なライブラリのWasmポート版が続々と開発されています。こういった動きによって、今までブラウザでやろうとすら思っていなかったことをブラウザ上で簡単に実現できる時が来るかもしれません。
──そうなんですね。ブラウザ以外だとどうでしょうか?
ブラウザ以外で活躍しそうな応用例の一つとしては、先ほど挙げた通りサーバーサイドのコードをWasmで書くというようなケースが考えられます。特に有用そうなケースとしては、例えばFaaS的なサービスが考えられます。FaaS (Function as a Service) とはユーザーの書いたコードをHTTPリクエスト等をトリガーとしてオンデマンドで実行するサービスの総称で、有名なものとしてはAWS Lambdaや、Google CloudのCloud Functionsなどがあります。このようなサービスは通常特定の言語のみに対応しているか、もしくはコンテナイメージを扱う形で言語非依存な実行環境を提供しているものが主流ですが、ここに第3の選択肢としてWasmを実行するタイプのものが台頭してくるかもしれません。
──それはなぜ?
Wasmを使うメリットとしては、コンテナイメージに比べて軽量であるためコールドスタート問題が緩和される可能性があることや、Wasmにコンパイルできる言語であればどんな言語で書いたプログラムでもFaaSに載せられる可能性があるという点、悪意のあるプログラムを実行されないようにクラウドベンダー側がサンドボックス的なものを用意するのが比較的容易な点などが挙げられます。また、軽量であるために通常のデータセンターよりもリソースの限られた場所、例えばエッジロケーションやIoT的な環境等でFaaSを提供するような場合に他の選択肢に比べて有利になる可能性があります。実際、例えばFastlyのCompute@Edgeや、CloudflareのWorkersなどのように、エッジロケーション上でWasmを動かすことができるFaaSのようなサービスは既に広く使われ始めています。
また、近い分野の例としてはKubernetesでWasmを動かすKrustletというものが開発されています。Krustletはkubeletの代わりとして動きますが、通常のコンテナイメージの代わりにWasmを実行します。使う側としては、通常のPodをデプロイするのと同じ感覚で、Wasmのアプリケーションを動かすことができるようになるというわけです。このプロジェクトはまだ安定版のバージョンをリリースしていないものの、広く使われるようになればKubernetesのエコシステムに大きな変化が訪れるかもしれません。
──以前浅野さんが解説してくれたKubernetesですね。
そうですね。また、先程述べたユースケースの最後の一つとして、アプリケーションのプラグインとしてWasmを使うというものがありました。Wasmは既にこのような例でも使われ始めていて、有名な例だとEnvoyがあります。Envoyはサービスメッシュ的な用途で使われるプロキシです。高トラフィックを捌ける性能とプラグインの柔軟性、プラグインのエラーによってEnvoy自体が落ちないような安定性などを考えると、WasmがEvnoyのプラグインを記述する手段として最適だったのかもしれません。その他にも、Wasmでポリシーを記述するKubernetesのポリシーエンジンであるKubewarden等も注目を集めています。
──Wasmをミクシィのプロダクトに活かすとなると、どういうところになるんですか?
Webサービスで提供されているものに関しては、いくらでも導入する余地があると思っています。わかりやすい分野としては、例えば見た目をちょっとリッチにしたいとか。画像認識や機械学習などをサーバー側じゃなくて、ブラウザ側で導入したい需要があるのであれば、役に立つかもしれないです。多分一番わかりやすいものとして、ゲームや動画関連、そのあたりな気もします。
──Webサービス以外だといかがでしょうか。
Webサービス以外でWasmを活用できるケースも多いと思います。例えば、近い将来に性能面やコストを考慮した上でサーバーサイドのロジックの一部、もしくは全部をWasmで動かすという選択が行われる可能性もあると思っています。それ以外にも、もっと身近なケースとしてはサーバーサイドでEnvoyを使っていてプラグインを書きたくなったみたいな場合とか。とはいえ、Wasm自体はアプリケーションのいわゆる機能要件に大きく関わってくるものではないので、ユーザーから見てWasmを導入することでここがこういう風になりますよ、というのは一概には言いにくいですね。
OSにもCPUにも依存しない。夢の技術?
──話を聞いていると画期的な技術に思えるのですが、爆発的に普及していくような技術なのでしょうか?
うーん、夢のような技術かと言われると、そういう類のものではないかなと思っていて。というのも、Wasmは既存の技術と比べて大きくかけ離れたアメージングな技術!というわけではなくて。既存の他の技術から一歩だけ進んだもの、という感じです。例えば、「OSにもCPUにも依存しない、比較的高速なバイトコード」という物自体はJavaが大昔から目指していたものですし、LLVM IRなんかも用途こそ違えど似たような例として挙げられます。ブラウザ上でJSより高速にプログラムを動かすという試みもNaClやasm.jsなどで数年前から行われています。また、プラグイン的な用途で用いられ、サンドボックス上で動くバイトコードとしても例えばeBPFのような既存技術があります。そういった既存技術と比べて、Wasmだけにしかできない飛び抜けたものがあるわけではありません。しかし、それでもWasmには強みがあります。それは、先程述べたWasmの性質、つまり、高速に動いて、CPUのアーキテクチャやOSに非依存で、特定の言語と密接に関連したVMではなくて、サンドボックス上で動かすことができて、ベンダー非依存で、チューリング完全で、プラグインとして使いやすいインターフェースがあって…といったものを全て満たすような技術でメジャーなものはWasmしかないと思います。ここがWasmの大きな強みです。
──では一般的な技術になっていく可能性もある。
また、普及するかしないかでいうと、Wasmは間違いなく普及すると思います。というのも、既にある需要に対して提供されている標準化された解決策だからです。例えば、今までブラウザ上でasm.jsを使ってCPUヘビーなプログラムを実行していたような場合、これをWasmに置き換えない理由はありません。とはいえ、全てのフロントエンドエンジニアがこのようなケースに当てはまるわけではありません。というのも、先程説明したとおり、普段JSやTypeScript (以下TS)を使ってWebアプリケーションを開発している人が、同じようなWebアプリケーションを作りたい場合、それはJSやTSを使えば実現できるわけです。こういう場合はWasmにわざわざ乗り換える必要があるわけではないので、そういう意味で信じられないような爆発的な普及をする類のものではないのかなと思っています。しかし、それでもフロントエンドで動くプログラムの大部分がWasmで置き換わるシナリオは発生しうると思っています。例えば、次に流行るAltJS的な言語やフレームワークが内部でWasmを多用している場合です。このようなケースでは、フロントエンドエンジニアは単純に特定の言語/フレームワークに移行することが目的で、Wasmを使うことを目的とするわけではないものの、結果的にWasmの使用率は上がっていきます。例としては、現時点で有名な候補としてもGoogleの「Flutter」やMicrosoftの「Blazor」などがあります。Flutterはユーザーの書いたDartのコード自体はJSにコンパイルするものの、レンダリングエンジンにはWasmを使うこともできます。一方Blazorはユーザーの書いたC#のコードをWasmにコンパイルします。これらのうちどちらか、あるいは全く新しいフレームワークが覇権を握り、結果としてWasmの普及率に大きく寄与するという可能性はあります。
──普及することで何かが大きく変わる可能性もあるのでしょうか?
例えば、Wasmの登場によって、これまでは存在しなかった要件がWebサイトに求められるスタンダードになってくる可能性があります。例えば、今より何倍もリッチなエフェクトが当たり前のように求められるようになった未来とか。それ以外にも、例えば広告収入の代替となる新たなWebサイトの収益源として、閲覧者に暗号通貨を採掘させるようなビジネスモデルが、法的にもクリアになってスタンダードになってくる可能性も無いとは言い切れません。このような状況下では、Wasmを使えないサイトはそうでないサイトに対して大きくビジネス上の遅れをとる可能性があります。そうなってきた場合、WebサイトにとってWasmを使うことが必須になってくるという未来も考えることはできます。
──ビジネスのスケールにも関わってくるかもしれないと。
とはいえ、この場合でもユーザーがWasmを使っていること自体を意識せずに済むようなフレームワークが整備されているかもしれないですけどね。
──エンドユーザーにはどのようなメリットがあるんですか?
やっぱりどの技術でも、新しい技術が生まれることによって、今までボトルネックになっていた部分などのパワーバランスが変わります。少し変われば、そのずれに気づいた人が、今まで誰も考えていなかったようなものを生み出すっていうのが、割とあるのかなと思います。
──具体的には…?
例えば、回線速度が速くなることで、今までテキストが主体だったサイトで、画像が使えるようになったりとか、今なら動画メインのサービスになったり…みたいな感じです。今までクライアントの端末でやるには、ちょっとだけCPUのリソースとかクライアントの性能が足りなくてできなかったことをWasmを使うことでやってのける人がでてきて、何かしらのパラダイムシフトが起こる。結果今までと全然違うアプリが流行り始める、みたいな可能性は十分にありますね。何か今までできなかったことができるようになる。ただそれはまだ誰にもわからない。
──逆に、明確な弱点みたいなものもあるのでしょうか?
現時点で「複数言語からコンパイルできてブラウザ上で動く高速な言語」として一定の成功を収めてはいるものの、改善の要求も多くあります。例えば、画像処理などでより高速な計算を行うためにSIMD命令が欲しいといった要求はよく目にします。SIMDとは単純な計算を複数の値に対して同時に行う操作のことです。大きなデータについて計算を行う場合、このような命令を活用することによって処理速度を向上することができます。ほとんど全てのCPUがこのような命令を提供しているのに対して、Wasmからこれらを使う部分については実験的な機能という段階です。(注:インタビューを行ったタイミングではそうだったものの、現時点ではWasmのSIMDに関する最初の提案は標準化されており、多くのブラウザで使うことができます。)他にも、言語仕様に関する機能として例外機能や末尾再帰最適化、ガベージコレクション等が提案されていたり、並行処理関連としてスレッドやアトミックな命令についての提案が上がっています。また、複数言語間や外側の環境と連携するための機能としてInterface Typesというものも提案されています。これらの機能が無くてもWasm自体は動きますが、より速くプログラムを実行したかったり、他の言語からWasmへのコンパイルをもっと効率的にしたいといった場合にはこういった機能が重要になってくる場合があります。
──発展の最中なわけですね。
あとこれは僕の主観になってしまうので、反論もらうかもしれないんですけど……、フロントエンド界隈からは思ったほど注目されていない気がしていて。とはいえ、そもそも元からTSやJSをメインで書いていたフロントエンジニアの多くの方にとっては、直接Wasmを使う必要性に迫られる機会というのは実はあまり多くないのかもしれません。
──使い分けの必要性はあまりないのでしょうか。
いいえ、むしろ積極的に使い分けていく必要はあると思います。ただ、両方使う必要のある人の割合というのは、意外と多くないのかもしれません。例えば、一部のライブラリだったり、計算量が気になってくるような部分のみがWasmで提供されていて、他の人達はそれらをライブラリとして使いつつ、自分たちの開発する部分はJSやTSで書いていく。そのような形の棲み分けがされる可能性はあるのかなと思っています
──最後に、Wasm以外に注目している技術はありますか?
Wasmとはあまり関係ないですが、これから勉強していきたい技術としてQUICが挙げられます。QUICは、UDPの上に構築された新しい通信プロトコルです。基本的にはTCP等に近いユースケースで使われるものと思っていただいて構いませんが、HOL Blockingの無い並列通信やコネクションマイグレーション等、現代のニーズに合わせた様々な機能を持っています。QUICもWasmと同様、導入することでエンドユーザーの体験に劇的な変化が訪れるという類のものではありません。しかし、これらの技術の導入によってアプリケーションで実現可能なもの、そうでないものの間の壁には何かしらの動きがあります。そして、このような変革はパラダイムシフトを生む可能性があります。こうした変化に積極的にキャッチアップして競合のサービスに遅れを取らないこと、さらには率先してパラダイムシフトを起こし競合との差別化を図ることが、toCの会社でのエンジニアが技術を追求する理由なのではないかと思います。