仕事でNode.jsを使ってます。サーバーでも使ってますし、Androidのモニタリングにも使っていたりします。
今回はサーバーの話。今更な感じもありますが、一応書いておきます。
Node.jsは早いの?遅いの?
単純作業で言えば早いです。「データベースから値を取ってきて、テンプレートに埋め込んで、HTMLを返す」みたいな単純作業は早いです。
でもそのHTMLから<img>タグがサーバを指していて、画像を返す処理もNode.jsにやらせると、どんどん遅くなっていきます。
画像やJavaScriptなど静的なファイルは別サーバにやらせて、Node.jsのサーバではプログラム的なことだけをやらせるようにすると上手くいきます。
仕事では、ウェブサイトはNode.js、静的なファイルはGoogle Cloud Storageにやらせてます。
以前に、2,000アクセス/秒のHTTPクエリをNode.jsに送ったら、何の問題もなくクリアしてました。
Apacheに同じことをしたら、レスポンスが遅いこと・・・。
Node.jsはシングルスレッド
Node.jsとApacheの最大の違いは、シングルスレッドで動くか、マルチスレッドで動くか、です。
Node.jsは「シングルスレッド」な分だけ、「コードが動く一瞬だけCPUを100%使用でき」ます。
Apacheの場合はマルチスレッドなので、ページアクセスがあるごとにスレッドを作って、みんな平等にCPUを割り当てて、処理をしていきます。
※あくまで概念の説明なので、細かいところは違います。
その分、Node.jsではある一つのコードが長々と処理をすると、待ち行列が発生します。
それを防ぐために、async.jsやPromiseを使うわけです。
つまりNode.jsでは「コードを小さい単位」で動かすのが吉。
シングルスレッド故に・・・
Node.jsのプログラムは「一筆書き」と思ってください。
プログラム全体がつながっているので、一箇所でエラーが発生すると、プログラム全体が死亡します。
それはあなたのコードではなくて、使っているモジュールの中で発生することも、よくあります。
なのでNode.jsでサーバを作るときは、プログラム全体が死亡してもすぐに立ち上がるようにする、ことが重要です。
foreverモジュールとか使ってしまえば簡単です。
後でいいことは後でやる
待ち行列を防ぐために、レスポンスとして返さなければいけないデータの生成に注力して、その他の作業は後回しにします。
例えば「BigQueryにログデータをStream APIを使って挿入する」みたいな後回しでいいことは、Redisデータベースを使って、一旦キャッシュを作っておき、別にプログラムを作って、crontaskなどを使ってあとから処理するようにします。
GCって効いているのか
最新版はどうなのかわかりませんが、少なくともv0.1x系はデフォルトでは有効ではないです。
有効にするには、node --expose-gc myapp.js
みたいな感じで動かします。
で、こんな感じでメモリ解放しています。
if ("gc" in global) {
setInterval(function() {
global.gc();
}, 5 * 1000);
}
foreverコマンドのときは、forever start -c "node --expose-gc" myapp.js
です。
1日1回くらいリスタートさせる
ずーっとNode.jsのプログラムを動かしておくと、2,3週間くらいすると、なんか調子が悪くなります。
プログラムをリスタートさせると、直ります。きっとメモリでしょうね。
なので、私のところは1日1回、明け方にリブートさせています。
いまのところ、こんな感じで問題はありません。誰かの参考になればと思って、書いてみました。