読者です 読者をやめる 読者になる 読者になる

Node.jsについてのよくある誤解

node.js

Node.jsは普及しそうに無い: ニュースの社会科学的な裏側

http://anlyznews.blogspot.com/2011/02/nodejs.html

という記事があったので、もしかしたらいい感じにNode.jsについてのよくある誤解がここに網羅されてるんじゃないかと思ってエントリを書きます。決して顔真っ赤にして反論してるわけじゃないよ!

で、まず

理由は簡単で、Googleがリリースしたアプリケーション・サーバーであるnode.jsが、JavaScriptとその実行エンジンを基本とした構成となっており、その性能が高いからだ。

とありますが、Node.jsはGoogle製ではありません。Node.jsがベースとしているJavaScriptのV8エンジンはGoogle製(のオープンソース)ですが、Node.js自身はJoyentという会社のサポートによって作られています。メインコミッタのRyan DahlもJoyentの社員です。
修正されてました!

あとは、

9. node.jsの問題点
高負荷時のパフォーマンスが優れているのは確かのようだが、現状では次のような欠点もある。万能薬的な使い方は出来ないようだ。

この項目について書けばいいと思うので各指摘点について書いていきます。っていうか、どのような言語であれどのようなフレームワークであれ得手不得手(もしくは適材適所)というものがあるので、万能薬は存在しないというのは一般的な共通認識ということでいいんじゃないのかな。Node.jsの開発者でNode.jsは万能だと言ってる人は誰一人みたことがないですし。

1. イベントループ・モデルで処理を直列化しているので、あるリクエストの処理に時間がかかる場合、他の全てのリクエストをブロックする可能性がある。

まず、この処理というのがI/Oを伴うものだと仮定すると、Node.jsはI/Oを非同期で行うためブロックは発生しません。他の非同期フレームワークであるTwisted(Python)やEventMachine(Ruby)などでは、組み合わせて使用するその言語のライブラリ次第でブロックが発生してしまうことがありますが、Node.jsは非同期であることが前提の環境なのでライブラリで同期I/Oが使われていてそれを同期呼び出しするようなケースはほぼありません*1
I/Oを伴わない部分だとすると、そのように時間のかかる処理(CPUインテンシブな処理)には向かないと言えます。ただ、一般的なWebアプリケーションであればI/O処理よりもCPU処理に時間のかかるケースというのはほとんどないのではないでしょうか。CPUがL1/L2キャッシュやRAMのみを用いて処理している場合とHDDやネットワークを用いる場合との差は、以下のエントリに端的に表現されています。

このブロックしてしまう処理というのはI/Oに端的に表れていて、たとえばCPUのL1キャッシュだと3サイクル、L2で14、RAMだと250で済むんだけど、それがDISKになると41,000,000サイクルかかって、ネットワークならさらに240,000,000サイクルもかかってしまうんだ。これがどのくらいすごいのかというと、サイクルをメートル換算してみるとわかりやすい。RAMでも250メートルでまだ目の届く範囲なんだけど、DISKになった瞬間、地球一周分、ネットワークだとさらに地球6周分!!!このコストの比はやっぱりトンデモナイんだよね。

http://d.hatena.ne.jp/badatmath/20101020/1287587240

あとはまあ、子プロセス作ってCPUインテンシブな処理はそっちにさせるってのも手ですね。

2. イベントループ・モデルで平行処理を行わないため、複数コアを持つCPU/MPU、複数のCPUを使うSMPでパフォーマンスの上昇が、JavaScriptのコード部分は期待できない。

これに関してもそういう理解をしている人は多いと思いますし、実際にNode.jsを1プロセスだけ立ち上げてる場合ではその通りです。しかし、Node.jsには複数の子プロセスを起動してそれらに処理を分散させるための様々なツール(ライブラリ)が既に存在し、使用実績もあります。例えば、fugue, Spark2, clusterなどです。これらを使えばコアの数だけプロセスを立ち上げ、リクエストをそのプロセスにロードバランスするみたいなことが簡単にできます。セッションの共有とかめんどいんじゃないかって思われるかもしれませんが、ExpressのようなConnectベースのWebアプリケーションであれば、connect-redisを使うなどすれば2行追加するだけでセッションの共有ができるようになります。

3. JavaScriptプログラミング言語としての限界が影響する。つまり、オブジェクト指向が不完全であること、動的型付けでJavaC#に対して速度面に限界があること等が、大規模で複雑なアプリケーションには影響を及ぼす可能性がある。

オブジェクト指向が不完全というあたりはちょっとよく分かりませんね。動的型付けで速度面に限界があることが大規模で複雑なアプリケーションに影響を及ぼすというのもよくわかりません。
どちらかというと、JavaScriptのプロトタイプベースのオブジェクト指向が、JavaC#などのクラスベースのオブジェクト指向しかやってこなかった人にとって慣れるのに時間がかかるとか、そういった問題はあるかとおもいます。また、動的型付けなのでIDEの支援が受けにくいとか多人数による開発であればきちんとルールを決めておかないと混乱を巻き起こす可能性があるとかそういったことはあるでしょう。ただ、前者についてはJavaScriptに慣れてる開発者も多いでしょうし、後者については他の動的言語でも大規模開発の実績があるのだから乗り越えられる障壁なんだと思っています。

4. あるページのJavaScriptの文法エラーが、サーバーの停止を引き起こす。簡単なプログラム・ミスが、アプリケーションの非クリティカルな部分に発生したとしても、システム全体がダウンする結果となる。

これはひどい誤解で、クライアント側の(HTMLから呼ばれる)JavaScriptが間違っていたからといって、サーバ側のNode.jsのプロセスが止まるなんてことはありません。それとも僕が誤読してるのかな?

追記:誤読してたっぽい。あるページの処理を行うサーバ側のJavaScriptでエラーが発生した場合のことだったみたいです。これも下のコメントに書かれているとおり、適切なエラー処理を行っていればNode.jsプロセス全体がダウンするなんてことはありません。

5. 非同期化によるパフォーマンス向上がイベントループ・モデルに依存するため、イベントを受けるコールバック関数が多くなり(単純なファイル操作でも3回コールバックが発生する)、ソースコードの見通しが悪くなる。

これもよくある指摘なんですが、様々な対処方があります。JavaScript自体に関しても、Future(Promise)を使ったパターンやDeferredを使ったパターンなどのライブラリも充実していますし、Node.jsについてもasync.jsなどの使い勝手のいいライブラリが数多く存在します(ちょっと前のエントリだけどhttp://d.hatena.ne.jp/koichik/20100926#1285502400参照)。

6. 利用可能ライブラリが限定的であり、開発支援ツールが無い。Apacheモジュールも種類や用途が多いし、JavaPHPにも覚えきれないほどのフレームワーク製品群とライブラリがある。これらに依存しない用途にしか、現状では利用できない。

利用可能なライブラリは確かに他言語に比べるとまだまだ少ないかもしれませんが、僕の個人的な感想では現状でもあまり不満はありません。また、既存のJavaScriptのライブラリ(例えばjQueryやYahoo!UIなど)は簡単にNode.jsから使うことができます。開発支援ツールという意味では、JavaScriptが使えるIDEやエディタなら大抵普通にコードは書けますし、Node Inspectorを使えばGUI環境でデバッグすることも可能です。ちなみにCloud9というNode.js製のIDEも存在し、これはローカルにインストールせずにホスティング環境で使うこともできます。
JavaPHPの誕生後1年でどれぐらいのライブラリやフレームワークが揃っていたかは知りませんが、生まれたての環境としては十分じゃないかなと思っています。ってか、欲しいのがあれば作ればいいだけだし、逆に言うと作って名を挙げるチャンスがあるとも言えますね。

終わりに

で、まあ上に書いたことは全部今書いてる本にもっと詳しく解説されています。というわけで出版されたら買ってね!という宣伝エントリでした。

*1:100%ではありませんが