2016年3月21日月曜日

Node.jsの問題点、デメリットと解決方法まとめ



技術選定のためや、俺が問題解決するぜっ!的な人向け。
順次解決されると思うので、順次更新します。
以下に上げたものも、解決策があるものが多いです。

はじめてのNode.js (2013年3月26日初版)

  • どこか1か所CPUリソースを多く消費するような重い処理が入ると、全体のパフォーマンスが低下する
  • マルチコア/マルチCPU環境を十分に生かすことができない 
  • コールバックを多用するためにコードが複雑になる

merittyの記事 (2012年12年23日)

  • JavaScriptの限界、オブジェクト指向が不完全
  • マルチコアサーバで性能を十分に発揮できない
  • 文法エラーが、サーバーの停止を引き起こす
  • あるリクエストに問題があると、他のリクエストをブロックする

ZEALOT社員の方 (2012年10月29日)

  • まだ商用で使うには不安定な部分がある。
  • 開発者が少ない。 : JavaScript開発者がNode.jsの開発者ではない。
  • メジャーでもない。
  • 非同期処理なのでエラーハンドリングが難しい。
  • 基本的にシングルプロセスなのでどこかでシステムエラーが発生するとサーバダウン。
  • Hot deployができない。

GREE CTO藤本さん (2012年8月)

  1. ひたすらすごい勢いでバージョンアップしているので安定しない。コストを払ってついていく覚悟を持って取り組んでいる。
  2. メモリリークがあるので、サーバを起動しっぱなしにするとメモリが食いつぶされる。
  3. コードをデプロイしても再起動しないと読み込まれない。
解決策は、上記リンク先に書いてあります。

IIJ

node-v0.6からはクラスターモジュールが導入され、Node.jsがマルチプロセスで動作するようになりましたが、マルチプロセスを意識してプログラミングの設計をする必要があります。
玉石混淆のユーザモジュール

デブサミ (2012年2月)

例えばNode.jsはI/Oや大量データ処理には強いものの、シングルスレッドでCPUパワーを使うようなタスクには弱い。そこで、結果はできるだけキャッシュするなどしてCPUリソースを節約する工夫が必要になる。HTMLのテンプレートやレンダリングなどはCPUリソースを消費するので、クライアントに処理を委譲してしまう対策も有効だという。 
データアクセスに関しては、Node.jsの処理は非常に高速だが、その分リクエスト回数が増えてDBに負荷を掛けることになる。そこで、制約をアプリケーションレベルで保持することによってDBの処理を低減しているという。
逆にNode.jsは、数値解析などプロセッサ処理が中心的となるような処理に対しては不適切
定期的に発生するV8エンジンのGC(ガベージコレクション

ブログ記事 (2011年2月20日)

  1. イベントループ・モデルで処理を直列化しているので、あるリクエストの処理に時間がかかる場合、他の全てのリクエストをブロックする可能性がある。
  2. イベントループ・モデルで平行処理を行わないため、複数コアを持つCPU/MPU、複数のCPUを使うSMPでパフォーマンスの上昇が、JavaScriptのコード部分は期待できない。
  3. JavaScriptのプログラミング言語としての限界が影響する。つまり、オブジェクト指向が不完全であること、動的型付けでJavaやC#に対して速度面に限界があること等が、大規模で複雑なアプリケーションには影響を及ぼす可能性がある。 4.あるページを表示するためのサーバー側のJavaScriptの文法エラーが、サーバーの停止を引き起こす。簡単なプログラム・ミスが、アプリケーションの非クリティカルな部分に発生したとしても、システム全体がダウンする結果となる。
  4. 非同期化によるパフォーマンス向上がイベントループ・モデルに依存するため、イベントを受けるコールバック関数が多くなり(単純なファイル操作でも3回コールバックが発生する)、ソースコードの見通しが悪くなる。
  5. 利用可能ライブラリが限定的であり、開発支援ツールが無い。Apacheモジュールも種類や用途が多いし、JavaやPHPにも覚えきれないほどのフレームワーク製品群とライブラリがある。これらに依存しない用途にしか、現状では利用できない。
上記、解決策は上記引用元や以下でも指摘があります。
Node.jsについてのよくある誤解 - 自分の感受性くらい

解決策

開発時の再起動問題

以下のモジュールを利用して、ファイル変更を検知して再起動する

本番サーバでのホットデプロイ問題

  • forever, up, pm2

コールバック地獄問題

  • future, promise, delay 並列処理のデザインパターンを使う future - Wikipedia
  • 定番の async.js を使う
  • yield を使う (Node.js version 0.12以降)

重い処理で処理が待たされる

  • child_process.fork(filepath)
  • fugue, Spark2, cluster
  • process.nextTick() (v.0.10.xまで?ループで一回処理ならこちら)
  • ループでn回の処理が必要なCPUヘビーな処理の場合、 setImmediate() 

マルチスレッド

文法エラーで止まっちゃう問題

  • 事前対策
    • 例外をキャッチする
    • Event: uncaughtException のリスナを登録
    • JSLint, JSHint等をコミットフックやデプロイ時に仕掛ける
    • ユニットテストを行う
  • 事後対策
    • 監視して再起動する

エラーハンドリング問題

調査が甘いので、偉い人教えて下さい。
  • 非同期コードの例外をキャッチする独自モジュール(node-gree)

メモリーリーク問題

  • node-v0.10.22 のファイルハンドラのメモリーリーク修正で解決? (コメントより。 thx shigeki@github)

時が解決する問題

  • 頻繁なバージョンアップ
  • 安定性問題 
  • Node.js 技術者が少ない
  • ドキュメントが少ない問題

偉い人が解決してくれるだろう問題

  • JavaScript の言語仕様の問題
    • オブジェクト指向

解決されていない問題

  • 玉石混淆のユーザモジュール
  • npm 上の評価システムの実装


14057 contribution
メモリリーク問題
先月行われた Web開発最前線テックトークにて @geta6 さんがv0.10でGCの方法がかわってメモリリーク問題は解決した的なことを言っていたような気がします。Node v0.10.0 (Stable) の "LATENCY AND IDLE GARBAGE COLLECTION" がそれに関する説明です。
そのときの発表資料は http://glide.so/geta6/eb28b1e3e14902fa8c74 でみることができます。
メモリリーク問題についてはスライド中で言及していないですが、最近のNode事情がまとまっているので見てみるといいかも知れません。
頻繁なバージョンアップや安定性問題
加えてこの問題についても前述の発表で言及していて Stability Index を見て怪しいやつを使わないようにすれば大丈夫らしいです。

37 contribution
Node v0.10.0 での GC 処理の変更は、 Node の I/O処理のアイドル時に GC 起動を通知することを止めただけで、メモリリークとは直接関係ないです。(状況によってはHeapの増加の仕方が変わるかと思いますけど。)
ちょうど今朝リリースされた node-v0.10.22でずっと気づかなかったメモリリークが解消されたので、頻繁にハンドルをオープン・クローズするような場合にはメモリ使用が改善されるかもしれません。

14057 contribution
なるほど!

5827 contribution
コメントありがとうございます。
記事をアップデートさせて頂きました。
0.10.22 のメモリーリークのパッチ、Pull Reqestを知りたく、GitHubで10分程探してみましたが、見つからず! めっちゃ探しにくいですね…
これからも最新情報取り込んで行きます!

37 contribution
修正コミットは https://github.com/joyent/node/commit/16934d9210546bf19d4af8d98652aa5d636ce693 です。
ただ注意していただきたいのは、今回たまたま Walmart の件でリークのバグが指摘され、修正されただけであって Node のメモリリーク(の存在する可能性)がまったくなくなったわけではありません。ソフトウェアですからバグが存在するのは避けられず、未知のバグや今後の修正で新しくバグでメモリリークが入り込む可能性もあります。
またブログ中でも書きましたが、単にGCされずにヒープが増加しているような状況をメモリリークと誤って認識していることがあります(個人的にはこの勘違いが一番多いと思ってます)。そのため 本当にメモリリークが発生しているのか特定することが一番重要だと思っています。

5827 contribution
Walmart メモリーリークをどのように見つけたか?詳しい話は、以下に書いてあります。
今後、メモリーリークが発生した時の調査に役立ちそうなので、シェア。
Walmart Node.js Memory Leak - Blog - Joyent
http://www.joyent.com/blog/walmart-node-js-memory-leak

386 contribution
昔のエントリへの突っ込みはご迷惑かも知れませんが……失礼します
まずタイポ。yieldがyeildになっています。
もひとつは「コールバック地獄問題」・「エラーハンドリング問題」。単に非同期のコーディングスタイルが知れ渡っていないことに根本があると私は思います。個人的にJavascriptの将来のため「コールバック地獄」という語彙そのものを殲滅したいので、【保存版】制御構造別非同期プログラミング完全制覇(サーバサイドJavascript・CoffeeScript)という記事を書いてみましたが、継続チェーンにおいても、再帰・例外・条件分岐・ループなどと同等の制御構造は(そこそこコンパクトに)記述可能なので、コールバック地獄なんてゆーのはやめよーよー、という趣旨のエントリです。
Cassandra
コメントを投稿する


0 コメント:

コメントを投稿