2004年から続くブログサービス「アメブロ」が2016年9月にシステムをリニューアル。本連載では、そこで取り入れた主要な技術や、その効果を紹介していく。今回は、React/Redux/Node.jsを使ったIsomorphic JavaScript特有のパフォーマンスチューニング手法や実際にあった問題および、その解決方法について。
2004年から続くブログサービスである「アメブロ」は、2016年9月にシステムをリニューアルしました。本連載「大規模ブログサイト表示速度改善 大解剖」では、そこで取り入れた主要な技術や、その効果を紹介しています。
アメブロのリニューアルでは、React/Reduxを採用し、サーバサイドとフロントエンド両方でのレンダリング、いわゆる「Isomorphic JavaScript」を導入しました。このようにさまざまな新しい技術を導入する上で、パフォーマンスは重要な課題です。
今回は全4回にわたる連載の最終回として、Isomorphic JavaScript特有のパフォーマンスチューニング手法や実際にあった問題および、その解決方法をお伝えします。
「アメブロ」リニューアルの最後に、負荷試験を実施しました。過去のアクセスログを負荷試験のデータとして利用し、「New Relic」と「Datadog」を使うことでレスポンスタイムやスループットを監視しました。
注意すべきは、この負荷試験のデータは全て従来のSSR(サーバサイドレンダリング)により生成されたページへのアクセスログだという点です。Isomorphic Web Applicationの場合、2ページ目からSPA(シングルページアプリケーション)になるので、SSRページへのアクセスが減少し、データにまつわるアプリケーションへのアクセスが大幅に増加することが想定されます。
「システム全体の中でSSRとSPAの割合が、どれぐらいあるか」、つまり「どれぐらいのユーザーが2ページ目に遷移するか」は、本番環境でないと推測が難しいので、ひとまずフルSSR時と同じ負荷をかけて検証していきました。
初めに「JMeter」を使って負荷をかけ始めましたが、負荷をかけた瞬間レスポンスタイムが一気に高騰し、負荷試験が全く進められない状態になりました。
そこで、ローカル環境で「ab(Apache Bench)」を使って確認すると、下図のようにパフォーマンスが非常に悪かったことが分かりました。また接続数と関係なく、スループットは常に1200rpmほどでした。
このままだと完全に使いものにならないので、これをきっかけにパフォーマンスチューニングを始めました。
2016年7月にNode.js 6.3.0がリリースされ、「--inspect」フラグが使えるようになりました。このフラグを使うと、Chrome経由でデバッグやプロファイリングが行えます。便利なツールなので、負荷試験1の結果を受けて、使ってみることにしました。
Node.jsサーバを起動するコマンドに「--inspect」を付与すると、専用のURLが表示されます。
このURLをChromeで開くと、Chrome Dev Toolが開きます。
「Profiler」タグを選択し、「Record JavaScript CPU Profiler」の「Start」をクリックして記録を始め、abなどのツールを使ってしばらく負荷をかけ続けます。最後に「Stop」をクリックしてプロファイラの結果を表示した結果、下記のようになっていました。これは、びっくりするほどNode.jsらしくない結果です。
Node.jsは、基本的な処理はmain threadで行われ、Event Loopを利用してノンブロッキングI/Oを実現します。一番時間がかかるI/O処理をEvent Loopに入れることで、結果が返されるまでの間に、並行して処理を実行できるようになります。
Event Loopの1周は「Tick」と呼ばれ、基本的に1回のTickの時間を短くすればするほど、パフォーマンスが良くなります。このプロファイラの結果を見ると、「renderToString()」メソッドは同期処理なので、非常に時間がかかることが分かりました。
平均1つの処理は40msぐらいかかるため、この処理を含める1回のTickの時間も長くなっています。そうすると、単位時間内のEvent Loopの実行数も少なくなり、全体のパフォーマンスが非常に劣化したことが分かりました。
このような重い処理へのよくある対応方法は「process.nextTick」メソッドや「setImmediate」メソッドを使い、1つの同期処理を複数回に分けて、非同期処理にすることです。ただReactの設計上、レンダリングは同期処理なので、修正することはほぼ不可能です。そこで、アメブロではrenderToString問題に対して、下記の解決方法を採用しました。
これから詳しく説明します。
Copyright © ITmedia, Inc. All Rights Reserved.