Kris Zyp「Multi-node: Concurrent NodeJS HTTP Server」
sitepen 2010.7.14ブログエントリ
Multi-node: Concurrent NodeJS HTTP Server
デフォルトでは実装されてないマルチコア対応をかんたんにするモジュールの紹介記事
- event emitter
- node.jsのイベントモデル?
- addListener()
がまだよくわかってないのに斜め読んだ
以下斜め読んだ内容
node.jsのtodoの1つはconcurrency
- node.js
- httpパーサーのアルゴリズムを最適化
- v8使ってる
- event-driveなアーキテクチャ
- node.jsのtodoとして、マルチコアのパワーの活用
- シングルプロセスでリクエストをさばいている
- node.jsに追加されたソケット共有機能
- このソケット共有とChild Processesを組み合わせる。
- tcpソケット1つで複数のプロセスを同時にさばけるように
- multi-node
- 自作したnode.jsモジュール
- node.jsサーバーでマルチプロセスを簡単に実装・利用できるのが目的
multi-coreモジュールの使い方
//よくあるチュートリアル通りに、httpモジュール読み込み、createServer()でサーバー用オブジェクト作る var server = require("http").createServer(function(request, response){ … standard node request handler … }); //通常はrequire("http").createSerer(function(){..}).listen(...) //と、メソッドチェーンでlisten()するが、ここでは違う //multi-nodeモジュール読み込んで、multi-nodeのlisten()メソッドへサーバー用オブジェクトを渡す var nodes = require("multi-node").listen({ port: 80,//listenするポート番号 nodes: 4//child processの数を指定 }, server);
- multi-nodeモジュールを使うと
- childプロセスの数は指定できる
- port番号も指定できる
- 自動的にchildプロセスを発生させ、共有されたtcpソケットをchild processへ渡す
- OSのカーネルはロードバランサとして動く
- 投げられるtcpリクエストを順番にchildプロセスへ(childプロセスがさばけるペースで)引き渡していく
- OSカーネルとは別にロードバランサを用意するよりも効率的
- プロセスがソケット接続を求める時だけソケット接続が実現される。
- ロードバランシングがダイナミックになる
- あるプロセスに負荷の高いリクエストが割り当てられてるとき、このプロセスへの追加リクエストは回避され別のプロセスで引き受けられる、という動きになる。
multi-nodeでchildプロセスの数はどうする?
- サーバーのcpuの数にあわせる
- よくあるアドバイス
- コンテキストスイッチ(context switch)オーバーヘッドも最小化される
- 常にそうともいえない
- コア数よりもプロセス数を少なくしたほうがいい場面
- マシンのリソースをnode.jsサーバに使い切るつもりがないとき
- プロセス数をコア数よりも多めにしたほうがいい場面
- 頻度の低い重いリクエストの次に軽めのリクエストが来る場面
- node.jsでは先行するイベントキューの処理が完了しないと次のキューの処理を開始しない。
- 重いリクエストをさばいているときに、プロセスが全部埋まってるときは待ち時間が発生する
- プロセスの粒度を小さくするために、プロセス数をコア数よりも増やしたほうがいいときがある。
- トレードオフを念頭において試してみるべき
- 一般にコア数よりもプロセス数を大きくしていけばコンテキストスイッチのオーバーヘッドも徐々に大きくなる
multi-nodeでは、プロセスとプロセスの間のコミュニケーションもサポート
- Cometのようなリアルタイムウェブアプリでは威力発揮する
- 真のリアルタイムチャット例だと・・
- あるプロセスが受信したメッセージを別のプロセスへ渡す
- セッションの管理がシンプルなアプリでも役立つ
- ブラウザがサーバーと同時に何個もコネクションを使えるようになると、ウェブアプリがサーバー上の別アプリへのアクセスがかんたんになる
- サーバー上のプロセス同士でセッションの共有もされる場合もある
- ブラウザがサーバーと同時に何個もコネクションを使えるようになると、ウェブアプリがサーバー上の別アプリへのアクセスがかんたんになる
multi-nodeモジュールでプロセス同士のコミュニケーションを使った例
//上のコード例の後半部分繰り返し。 //モジュールロードして、サーバー用オブジェクトをlisten()メソッドに渡すとこまで。 var nodes = require("multi-node").listen(…); //listen()で返されたサーバ用オブジェクトにリスナーをつける。addListener()使う //新たにプロセス(Node Process)が作られると、nodeイベントが発火。 //発火時に渡されるstreamオブジェクトを使ってプロセス間のデータのやりとりができる nodes.addListener("node", function(stream){ stream.addListener("data", function(data){ … receiving data from this other node process … stream.write(… write data to other process…); }); });
まとめ
- multi-node使うとnode.jsのソケット共有機能が簡単に使えて、concurrency実やスケールアウトがやりやすくなる
- multi-nodeモジュール自体は、Persevereのサブプロジェクト
- Persevere=Dojoをフロントエンドに使うウェブアプリのフレームワーク?
- persevere-example-wiki
- このページでPersevereとmulti-nodeをかんたんに組み合わせるためのtips書いてるから読んでくれ
- Tunguska
- Persevereのサブプロジェクトの1つ
- multi-nodeで実装したマルチプロセスを、スケールアウトできるリアルタイムウェブアプリ用のフレームワーク
- node.js以外にも他のサーバーサイドJS(Rhino/Narwhal)でも動かせるらしい