PHP
v8
React
ssr
v8js

V8JsのスナップショットでSSRを高速化

More than 1 year has passed since last update.

V8JsはPHPの機能拡張でGoogle V8 JavaScript EngineをPHPに組み込みます。PHPから直接JSのコードが実行できます。

V8はとても高速ですが、PHPから利用する場合にそのインスタンスの生成コストとサイズの大きいJSライブラリの初期化のコストが気になります。

V8のスナップショット

V8のスナップショットの機能を使うと、Reactなどのライブラリコードやアプリケーションのコードがbuilt-inのコードとしてV8の初期状態から利用可能になります。PHPのV8Jsも対応していて、大幅なパフォーマンスアップが可能です。

snapshot がコンパイル済みの built-in の JavaScript のコードを含むシリアル化されたヒープを持つため、最初の context を作る時間は高度に最適化される。extensive caching は GC と同様に V8 のパフォーマンスのキーである。 - https://javascript.g.hatena.ne.jp/edvakf/20100407/1270626241

image
http://stesie.github.io/2016/02/snapshot-performance

このグラフはV8Jsの作者のstesieさんのブログ 20x performance boost with V8Js snapshots からのものです。

5.0.104-bassnapの青いバーがV8Jsインスタンス生成するコストで、赤いバーがReactJsのコードの読み込みコストです。スナップショットを使えば、読み込みコストがnewの時に発生するためインスタンス生成コストはやや上昇しますが、Reactのコードのコストは無くなります。(一番右)。縦軸はミリ秒で、PHPからのJSの利用コストがとても低いことがわかります。

スナップショットの種類

スナップショットは外部にもつか内部に持つか、2つの種類があります。パフォーマンスに優れるのは内部ですが、V8のコンパイル時にJSのコードから出力したスナップショットを含める必要があります。詳しくはREADMEをご覧ください。デフォルトは外部です。

スナップショット作成

外部のスナップショットの作成はcreateSnapshot()で行います。PHPのマニュアルには無いですが、GithubのREADMEのPHP APIに記載されています。

$blob = V8Js::createSnapshot(file_get_contents(__DIR__ . "/react.bundle.js"));
file_put_contents(__DIR__ . '/snapshot_blob.bin', $blob);

スナップショット読み込み

$blob = file_get_contents(dirname(__DIR__, 2) . '/tmp/snapshot_blob.bin');
$v8 = new V8Js('PHP', [], [], true, $blob);

これもPHPのマニュアル V8Js::__constructには4つまでの引数しかありませんが、5つ目にV8Js::createSnapshotで作成した$snapshotを渡します。

テスト

テストコードを作成してみました。

https://github.com/koriym/v8js-benchmark

new V8Js without snapshot ........ 6.529 msec .. 4,252.041 points ....... 71.56% ......... 1.00x
new V8Js with snapshot ........... 9.124 msec .. 5,941.913 points ...... 100.00% ......... 1.40x

executeString() with snapshot ........... 0.174 msec .... 117.127 points ........ 2.52% ......... 1.00x
executeString() without snapshot ........ 6.911 msec .. 4,646.427 points ...... 100.00% ........ 39.67x

V8 + internal snapshot ......... 7.459 msec .. 4,961.625 points ....... 10.41% ......... 1.00x // simulated
V8 + external snapshot  ....... 26.858 msec . 17,866.169 points ....... 37.48% ......... 3.60x
V8 ............................ 71.668 msec . 47,674.422 points ...... 100.00% ......... 9.61x

executeString()では40倍と大きな差はありますが、これはReactのコードをこの時点で実行しているためです。"internal snapshot"は、内部snapshotがあるV8と素のV8を同じ生成コストと仮定しての値です。外部スナップショットの3.6倍早く、スナップショットを使わない場合の約10倍速い数値になっています。

結論

PHPのV8Jsは決して実験レベルのものではなく、スナップショットの機能を用いれば驚異的な低オーバーヘッドで2つの言語を繋ぐ優れたPHP拡張です。expressでサーバーを起動する必要がなく、スカラー値のみならず、オブジェクトやクロージャーを直接双方向に渡すことができます。

アクティブにメンテナンスされてる作者のStefan Sieglさんに感謝。ReactJSやVue.jsのSSRに使用するだけはなく、豊富なJSのライブラリと高速なV8エンジンを活用してPHPと新しく創造的な連携ができるのではないでしょうか。

こちらの投稿もご覧ください。