本セッションの登壇者
セッション動画(YouTubeチャンネル登録もお願いします。)
よろしくお願いします。伊藤です。Node.jsパフォーマンスチェックポイントというタイトルでLTをさせていただきます。
Node.jsはフロントエンドと同じJavaScriptでバックエンドを記述できるため、フロントエンドを主戦場とするエンジニアもバックエンドに関わりやすいというメリットがあります。
ですが、フロントエンドとバックエンドではパフォーマンスの向上に関して必要な観点が、少し異なります。今回は自分がいつもアプリケーションを作成する際に気を付けているポイントについて、皆さんと共有できればと思います。
Node.jsの特徴
Node.jsを特徴づける大きなポイントは、非同期のイベント駆動型ランタイムとノンブロッキングI/O、シングルスレッドという点です。
これらを実現するために、Node.jsはV8というJavaScriptエンジンと、libuvという非同期のI/Oのライブラリが組み合わされています。JavaScriptの世界とI/Oをつなぐためにイベントループという仕組みも導入されています。
したがって、このイベントループを停止させてしまうとアプリケーション全体のパフォーマンスが低下してしまいます。なので、JavaScriptアプリケーションのパフォーマンスは多くの場合がイベントループを停止させないという点に集約されていきます。
パフォーマンスチェックの5つのポイント
実際に私がパフォーマンスのチェックをする際にまず確認する項目がこちらです。ひとつずつ説明していきます。
○同期関数の利用がないか
ひとつめは同期関数の利用がないかのチェックです。同期関数はイベントループを停止させる処理になります。なので、リクエストごとに同期関数が実行されていないか、全体を流して確認をします。
たとえばここに載っているサンプルでは、リクエストごとにHTMLファイルを読み込んでしまっているため、リクエストのためにサーバが一時停止してしまいます。一度だけ実行すれば良い処理であれば、サーバ起動時に一度だけ呼び出されるように変更します。もしくはreadfileのように非同期関数が用意されている場合は、そちらを利用するように変更します。
○巨大なJSONを扱っていないか
次にJSONの処理をチェックします。
APIのリクエストなどどうしても回避できないようなものもあるので、完全にゼロにするのは難しいですが、何度も実行されていないかをチェックします。ライブラリの内部で使われていることも多かったりするので、意外と気づかないままパフォーマンスが低下していた…ということもよくあります。
また、JSONのサイズも気にするポイントです。最初は問題なかったAPIが、データ量が増えるに従ってJSONがそのまま大きくなっていき、パースでいつの間にかパフォーマンスが低下していたということがままあります。私は最大でも1MB以下ぐらいになるように設計するということを目安にしています。
○長いループがないか
ループ処理も基本的には同期処理です。JSONの処理と同様に完全に排除はできないんですが、 1つのループが長くならないように気を付けてます。
こちらも最初は問題なかったけど運用してるうちに出た量が増えて、いつの間にかすごく長くなってしまったということが起きがちなので、ループ処理ごとに長くなっていないかを確認します。
たとえば1万ループを回すのは嫌なので、100ループごとにデータを取得するように変更するなどです。もしくはそういったケースではNode.jsのStreamが生きる場面なので、Stream化できないかを検討します。
最近ではAsync Iteratorが普通に使えるようになってきたので、Streamをベースに考え始めることが多いです。
○追加デプロイ先が自前サーバの場合
ここまではどんな環境でも気をつけているポイントです。ここからは自分でサーバを準備しているときのポイントを説明します。
自分でサーバを用意する時はクラスタ化しているかと、ファイルディスクリプタの設定が適切かというポイントをチェックします。
ただ、最近はCaaSやPaaSにデプロイすることも増えたので、このあたりをチェックしないことも増えてきました。CaaS/PaaSの場合はサーバリソースを使い切ることを考えるより、横に並べたほうがいいパターンも多いためです。
クラスタはマルチコアを利用できるようにするモジュールです。簡単に言ってしまえばfork数分のパフォーマンスが向上します。ただ、CPU数までフォークしてしまうと、万が一アプリケーションが暴走したときにsshもできなくなっちゃった、みたいなことが起きたりするので、私の場合はCPU数の半分やマイナス1くらいで設定することが多いです。
ファイルディスクリプタの数値もサーバにデプロイする際は重要です。Node.jsは1つのプロセスでリクエストを受けるため、1プロセスが大量のファイルを扱うことになります。なので、ファイルディスクリプタの上限値がデフォルトだと足りなくなりがちです。
たとえば右のように1024とかだとNode.jsには全然足りません。これを十分大きな値となるように設定します。
○最新のLTSを利用しているか
最後に、あたりまえのような話なんですが、最新のLTSを使っているかという点も重要です。
最初の特徴で言ったようにNode.jsはV8というJavaScriptエンジンで動作します。つまりV8が速くなればアプリも自動的に速くなります。
あとはバージョンアップで大きく高速化したりするので、なるべく最新のLTSに常に追従できる状況を保っておくのが、パフォーマンスの観点ではかなりコスパの良い対策だと思っています。
この辺はV8ブログを眺めるのが非常にお勧めなので、興味ある方は覗いてみてください。
まとめ
以上、アプリケーションのパフォーマンスを保つために私が必ずチェックしてるポイントについてまとめました。
実際の運用ではこれに当てはまらないことも数多く出てくるんですが、まずここを調べるというチェックポイントを持っておくと、それ以外の原因があったときにも絞り込みやすいと思います。
少しでも皆さまの運用負荷が減る手助けになれば嬉しいです。
ご清聴ありがとうございました。