web-dev-qa-db-ja.com

マルチコアマシン上のNode.js

Node.js は面白そうです、しかし私はなにか見逃しているはずです - Node.jsではありません単一のプロセスとスレッドで実行するように調整された?

それでは、マルチコアCPUとマルチCPUサーバーにどのように対応しますか。結局のところ、可能な限りシングルスレッドサーバーを高速化するのは素晴らしいことですが、高負荷の場合は複数のCPUを使用したいと思います。また、アプリケーションの高速化にも同じことが言えます。今日では、複数のCPUを使用してタスクを並列化する方法が使用されているようです。

Node.jsはこの絵にどのように適合しますか?どういうわけか複数のインスタンスを配布するという考えですか、それとも何ですか。

559
zaharpopov

[この投稿は2012-09-02現在で最新です(上記よりも新しい)。]

Node.jsはマルチコアマシンでは絶対に拡張できます。

はい、Node.jsはプロセスあたり1スレッドです。これは非常に慎重な設計上の決定であり、ロックセマンティクスを扱う必要性を排除します。これに同意しないのであれば、マルチスレッドコードをデバッグするのがどれほど難しいか、まだ気付いていないでしょう。 Node.jsプロセスモデルと、それがなぜこのように機能するのか(そしてなぜそれが複数のスレッドをサポートしないのか)のより深い説明については、 my other post を読んでください。

じゃあどうやって私の16コアボックスを利用するのですか?

二通り:

  • 画像のエンコーディングのような大規模な計算タスクの場合、Node.jsは子プロセスを起動したり、追加のワーカープロセスにメッセージを送信したりできます。この設計では、1つのスレッドでイベントの流れを管理し、N個のプロセスで重い計算タスクを実行し、他の15個のCPUを使い分けることになります。
  • Webサービスでスループットを拡張するには、1つのボックスで複数のNode.jsサーバーをコアごとに1つずつ実行し、それらの間で要求トラフィックを分割する必要があります。これにより、優れたCPU親和性が得られ、スループットはコア数とほぼ直線的に比例します。

Webサービスのスループットを拡張する

V6.0.X以降、Node.jsには そのままクラスタモジュール が含まれるようになりました。これにより、単一のノードで待機できる複数のノードワーカーを簡単に設定できます。港。これは npm で利用できる古いlearnboostの "cluster"モジュールと同じではないことに注意してください。

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  http.Server(function(req, res) { ... }).listen(8000);
}

労働者は新しい接続を受け入れるために競争し、最も負荷の少ないプロセスが勝つ可能性が最も高いです。それはかなりうまく機能し、マルチコアボックスでスループットをかなりうまくスケールアップすることができます。

複数のコアを気にするのに十分な負荷がある場合は、さらにいくつかのことをしたいと思うでしょう。

  1. Nginx または Apache のようなWebプロキシの背後でNode.jsサービスを実行します - 接続スロットルを実行できるもの(あなたが過負荷状態でボックスを完全に停止させたくないのであれば)URLを書き換え、静的コンテンツを提供し、そして他のサブサービスを代理する。

  2. 定期的にあなたのワーカープロセスをリサイクルしてください。長時間実行されているプロセスでは、わずかなメモリリークでも最終的には合計されます。

  3. セットアップログの収集/監視


シモンズ:アロンとクリストファーの間で、別の記事のコメントで議論があります(この記事の執筆時点では、その一番上の記事)。そのいくつかのコメント:

  • 共有ソケットモデルは、複数のプロセスが単一のポートで待機し、新しい接続を受け入れるために競合できるようにするのに非常に便利です。概念的には、各プロセスは単一の接続しか受け入れずに終了するという重要な注意点を伴って、これを実行している先送りのApacheを考えることができます。 Apacheの効率の低下は、新しいプロセスをフォークすることによるオーバーヘッドにあり、ソケット操作とは無関係です。
  • Node.jsにとって、N人の作業者が単一のソケットで競合することは非常に合理的な解決策です。別の方法としては、Nginxのようなオンボックスフロントエンドを設定し、そのプロキシトラフィックを個々のワーカーに渡して、新しい接続を割り当てるためにワーカーを交互に切り替えることです。 2つのソリューションは、非常によく似たパフォーマンス特性を持っています。そして、上で述べたように、とにかくあなたがノードサービスの前にNginx(あるいは代替手段)を置きたいと思うかもしれないので、ここでの選択は本当に間にあります:

共有ポート:nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

vs

個別のポート:nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}

個々のportsの設定にはおそらく確かにいくつかの利点があります(プロセス間のカップリングが少なくなり、より高度なロードバランシングの決定などができる可能性があります)。ほとんどの人のために働く - 複雑さの選択肢。

668
Dave Dopson

1つの方法は、サーバー上でnode.jsの複数のインスタンスを実行してから、それらの前にロードバランサ(できればnginxのような非ブロック化インスタンス)を配置することです。

41
Chandra Sekar

Ryan Dahlは、この質問に 彼がGoogleで行ったテクニカルトーク で答えています。言い換えれば、「複数のノードプロセスを実行し、それらが通信できるように賢明なものを使用するだけです。たとえば、sendmsg()スタイルIPCや従来のRPCなど)。

手をすぐに汚したい場合は、 spark2 永遠に モジュール。これにより、複数ノードプロセスの生成が簡単になります。ポート共有の設定を処理するので、それぞれが同じポートへの接続を受け付けることができます。また、プロセスが確実に再開された場合に、プロセスが確実に再開されるようにする場合は、自動再起動も可能です。

UPDATE - 10/11/11Cluster は、マシンごとに複数のノードインスタンスを管理するための優先モジュールになりました。 永遠に も見る価値があります。

30
broofa

clusterモジュールを使うことができます。これをチェック してください

var cluster = require('cluster');
var http = require('http');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    // Workers can share any TCP connection
    // In this case its a HTTP server
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end("hello world\n");
    }).listen(8000);
}
16
Sergey Zhukov

マルチノードはあなたが持っているかもしれないすべてのコアを利用します。
http://github.com/kriszyp/multi-node をご覧ください。

より簡単なニーズのために、異なるポート番号でノードの複数のコピーを起動し、それらの前にロードバランサーを置くことができます。

13
CyberFonic

上で述べたように、 Cluster はすべてのコアに渡ってあなたのアプリを拡張し、負荷分散します。

のようなものを追加する

cluster.on('exit', function () {
  cluster.fork();
});

失敗したワーカーを再起動します。

最近では、多くの人が PM2 を好んでいます。これは、クラスタリングを処理し、 いくつかの優れた監視機能を提供します

次に、クラスタリングを実行している複数のマシンの前にNginxまたはHAProxyを追加すると、複数レベルのフェイルオーバーとはるかに高い負荷容量が得られます。

10
Will Stern

Nodeの将来のバージョンでは、プロセスをフォークしてメッセージを渡すことができるようになるでしょう。Ryanは、ファイルハンドラも共有する方法を見つけたいと述べているので、これは単純なWeb Workerの実装ではありません。

現時点ではこれに対する簡単な解決策はありませんが、それはまだ非常に早い段階であり、nodeは私が今まで見た中で最も速く動いているオープンソースプロジェクトの1つです。

7
mikeal

Node JsはあなたのCPUを最大限に活用するためにクラスタリングをサポートしています。あなたがクラスタでそれを実行していないのであれば、おそらくあなたはあなたのハードウェア機能を無駄にしています。

Node.jsでのクラスタリングにより、同じサーバーポートを共有できる別々のプロセスを作成できます。たとえば、ポート3000で1つのHTTPサーバーを実行している場合、それはプロセッサのシングルコアのシングルスレッドで実行されている1つのサーバーです。

以下に示すコードを使用すると、アプリケーションをクラスタ化できます。このコードはNode.jsによって表される公式のコードです。

var cluster = require('cluster');
var numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
    // Fork workers.
    for (var i = 0; i < numCPUs; i++) {
        cluster.fork();
    }

    Object.keys(cluster.workers).forEach(function(id) {
        console.log("I am running with ID : " + cluster.workers[id].process.pid);
    });

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {

    //Do further processing.
}

この記事で完全な チュートリアル を確認してください。

7
Toumi

Spark2はSparkをベースにしたもので、現在はメンテナンスされていません。 Cluster はその後継であり、CPUコアごとに1つのワーカープロセスを生成したり、死亡したワーカーを再生成したりするなど、いくつかの優れた機能を備えています。

7
TheDeveloper

ここでブロックの新しい子供はLearnBoostの "Up" です。

それは "ゼロダウンタイムリロード"を提供し、さらにすべての世界の最高を提供するために複数のワーカー(デフォルトでCPUの数ですが、それは設定可能です)を作成します。

それは新しいですが、かなり安定しているようです、そして私はそれを私の現在のプロジェクトの1つで楽しく使っています。

5
Roy

私は Node worker を使って私のメインプロセスから簡単な方法でプロセスを実行しています。私たちが公式のやり方でやってくるのを待っている間、とてもうまくいっているようです。

5
christkv

cluster モジュールはあなたのマシンのすべてのコアを利用することを可能にします。実際、非常に一般的なプロセスマネージャ pm2 を使用することで、コードに触れることなく、わずか2つのコマンドでこれを利用できます。

npm i -g pm2
pm2 start app.js -i max
2
Alister

cluster モジュールと os モジュールを組み合わせて使用​​することで、node.jsアプリケーションを複数のコアで実行できます。あなたが持っているCPUの数を検出します。

たとえば、バックエンドで単純なhttpサーバーを実行するserverモジュールがあり、それを複数のCPUで実行したいとします。

// Dependencies.
const server = require('./lib/server'); // This is our custom server module.
const cluster = require('cluster');
const os = require('os');

 // If we're on the master thread start the forks.
if (cluster.isMaster) {
  // Fork the process.
  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }
} else {
  // If we're not on the master thread start the server.
  server.init();
}
1

それぞれ1つのNodeJSプロセスを実行している複数のボックスの前に、純粋なTCPロードバランサー(HAProxy)を使用して、NodeJSを複数のボックスにスケールアウトすることが可能です。

その後、すべてのインスタンス間で共有する共通の知識がある場合は、中央のRedisストアなどを使用して、すべてのプロセスインスタンスから(たとえばすべてのボックスから)アクセスできます。

0
Martin Tajur

Webサービスを、UNIXソケットを待機する複数のスタンドアロンサーバーとして設計することもできます。そのため、データ処理などの機能を別々のプロセスにプッシュできます。

これは、cgiプロセスがビジネスロジックを処理してから、UNIXソケットを介してデータベースにデータをプッシュおよびプルする、ほとんどのスクリプト/データベースWebサーバーアーキテクチャに似ています。

違いは、データ処理がポート上で待機しているノードWebサーバーとして記述されていることです。

それはより複雑ですが、最終的にはマルチコア開発が行かなければならないところです。 Webリクエストごとに複数のコンポーネントを使用するマルチプロセスアーキテクチャ。

0
Fire Crow