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


606

Node.jsのは面白そうだね、しかし私は何かを欠場しなければならない-のNode.jsだけ単一のプロセスやスレッドで実行するように調整されていませんか?

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

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


4
Ryahが組み込みのマルチコアサポートをノードに含めることについて真剣に取り組んでいるようです:github.com/joyent/node/commit/…– broofa
10/13 21:37

2
:PM2プロセスマネージャの使用クラスタモジュールは、内部的に利用可能なすべてのコアにごNodeJSのアプリを広めるためにgithub.com/Unitech/pm2
ユニテック

@broofa、それらは実際のスレッドではなく、子プロセスには共有メモリがありません。また、Javaの実際のスレッド化および揮発性静的変数に対応するNodejsとは何ですか?
パセリエ2017

回答:


697

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

Node.jsは、マルチコアマシンで完全にスケーリングします。

はい、Node.jsはプロセスごとに1つのスレッドです。これは非常に慎重な設計上の決定であり、ロッキングセマンティクスを処理する必要がなくなります。これに同意しない場合、マルチスレッドコードのデバッグがいかに非常に難しいかをまだ理解していないでしょう。Node.jsプロセスモデルの詳細な説明、およびNode.jsプロセスモデルがこのように機能する理由(および複数のスレッドをサポートしない理由)については、他の投稿を参照してください

では、16コアボックスを活用するにはどうすればよいですか?

二通り:

  • 画像のエンコーディングのような非常に重い計算タスクの場合、Node.jsは子プロセスを起動したり、追加のワーカープロセスにメッセージを送信したりできます。この設計では、イベントのフローを管理する1つのスレッドと、重い計算タスクを実行し、他の15個のCPUを消費するN個のプロセスがあります。
  • Webサービスのスループットをスケーリングするには、1つのボックスで複数のNode.jsサーバーをコアごとに1つ実行し、リクエストトラフィックをサーバー間で分割する必要があります。これは優れたCPUアフィニティを提供し、コア数とほぼ直線的にスループットをスケーリングします。

Webサービスでのスループットのスケーリング

v6.0.X以降、Node.jsにはそのまますぐにクラスターモジュールが含まれるため、単一のポートでリッスンできる複数のノードワーカーを簡単に設定できます。これは、npmを介して利用できる古いlearnboost "クラスター"モジュールと同じではないことに注意してください。

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

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

複数のコアを気にするのに十分な負荷がある場合は、さらにいくつかのことを実行する必要があります。

  1. Node.jsサービスをNginxApacheなどのWebプロキシの背後で実行します。これは、接続の絞り込み(過負荷状態によってボックスを完全にダウンさせたくない場合)、URLの書き換え、静的コンテンツの提供、その他のサブサービスのプロキシを実行できるものです。

  2. 定期的にワーカープロセスをリサイクルします。実行時間の長いプロセスの場合、小さなメモリリークでも最終的には加算されます。

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


PS:アーロンとクリストファーの間の別の投稿のコメントでの議論があります(この執筆時点で、そのトップの投稿)。それに関するいくつかのコメント:

  • 共有ソケットモデルは、複数のプロセスが単一のポートでリッスンし、新しい接続の受け入れを競うことを可能にするのに非常に便利です。概念的には、フォークされたApacheがこれを行うと考えると、各プロセスは単一の接続しか受け入れずに終了するという重要な警告があります。Apacheの効率の低下は、新しいプロセスの分岐によるオーバーヘッドであり、ソケット操作とは何の関係もありません。
  • Node.jsの場合、N個のワーカーを単一のソケットで競合させることは非常に合理的なソリューションです。別の方法として、Nginxのようなオンボックスのフロントエンドをセットアップし、個々のワーカーへのプロキシトラフィックを使用して、ワーカー間で交互に新しい接続を割り当てます。2つのソリューションのパフォーマンス特性は非常に似ています。そして、上で述べたように、とにかくNginx(または別の方法)がノードサービスの前に立つことを望んでいるため、ここでの選択は本当に次のいずれかになります。

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

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

個々のポートのセットアップには間違いなくいくつかの利点があります(プロセス間のカップリングが少ない可能性、より高度なロードバランシングの決定などがある可能性があります)が、セットアップするのは間違いなく多くの作業であり、組み込みのクラスターモジュールは低い-ほとんどの人のために働く複雑な代替手段。


1
1つのボックスでさまざまなnodejsベースのサービスを実行するためのアドバイスを提供できますか?たとえば、1つのサーバーがあり、CpuCore1でmyservice1.jsを実行し、CpuCore2でmyservice2.jsを実行するとします。このためにクラスターを使用できますか?またはそれはクローンされたサービスを作成するためにのみ有用ですか?
UpTheCreek 2012

6
そのための質問を投稿してください!(そして、私はあなたの最初の答えとしてこのコメントをコピーします)。あなたがしたいことは実際には本当に本当に簡単です。実際には「クラスター」は必要ありません。2つの異なるノードサービスを実行するだけです。2つのスクリプト、2つのプロセス、2つのポート。たとえば、serviceAを3000でリッスンし、serviceBを3001でリッスンすることができます。これらの各サービスは「クラスター」を使用して1以上のワーカーを持ち、定期的にリサイクルします。その後、ポート80でリッスンして転送するようにNginxを設定できます。着信「ホスト」ヘッダーおよび/またはURLパスに基づく正しいサービス。
Dave Dopson、2012

1
ありがとう。私はすでに関連質問投稿しました -私が念頭に置いていたものをほとんど説明しましたが、CPUコアをターゲットにする方法がわかりません(永遠に使用する場合など)。
UpTheCreek 2012

素晴らしい答えのドプソン。2つのノードプロセスを同じマシン上で互いに通信させる最良の方法は何ですか?同じマシン上にある場合、TCPよりも高速なプロトコルはありますか?
winduptoy 2013年

1
@Serob_b-まあ、はい。Node.jsアプリを複数のマシンで実行することは非常に一般的です。そのために必要なライブラリはありません。複数のマシンでコードを実行し、それらの間で負荷を分散するだけです。スケーリングできるようにソフトウェアを設計する(つまり、状態をメモリに保持するのではなく、ある種の外部データサービスに状態を格納する)-それがあなたの仕事です。
Dave Dopson、2017年

45

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


36
node.jsはnginxとほぼ同じくらい高速です。必要に応じて、node.jsサーバーの前にnode.jsロードバランサーを配置することもできます:)
mikeal

26
ライアンはノードがより安定するまでこれをしないように特に言いました。最良の方法は、ノードの前でnginxを実行することです。
resopollution 2010

2
ノードの前のnginxに関しては、メモリ内キューがある場合のような特定の問題を解決しません。2つのノードインスタンスが互いのキューにアクセスできなくなります。
resopollution 2010

5
同様に、nginxはHTTP 1.1を完全にはサポートしていないため、WebSocketのようなものはプロキシできません。
ashchristopher

2
@ mikeal、resopollution-私は強くNginx側にいます。Node.jsを何度もハードクラッシュしました(スタックトレースなし、ただ死ぬ)。Nginxをクラッシュさせたことはありません。Nginxは、すべての種類の正常なスロットルで構成されています。Node.jsは、デフォルトでは、ボックスがダウンするまで既存の接続よりも新しい接続を優先して受け入れます...はい、ボックス全体。ノードのストレステストを行って、CentOS5ボックスのカーネルをクラッシュさせました(現在、これは実際には起こりません)。私は少し思い付きましたが、Nodeには明るい未来があり、専用のLBタイプの役割が含まれる可能性があります。まだです。
Dave Dopson 2013年

30

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

すぐに手を汚したい場合は、spark2 Foreverモジュールをチェックしてください。これにより、複数のノードプロセスの生成が簡単になります。ポート共有の設定を処理するので、それぞれが同じポートへの接続を受け入れることができ、プロセスが停止した場合や停止したときにプロセスが確実に再起動されるようにするには、自動再生成も行います。

更新-11/11/11:ノードコミュニティのコンセンサスは、クラスタが現在、マシンごとに複数のノードインスタンスを管理するための優先モジュールであるということです。 いつまでも一見の価値があります。


8
ForeverとClusterは非常に異なることを行います。両方を使用することもできます。プロセスが停止すると、プロセスは永遠に再起動します。クラスターは複数のワーカーを管理します。Foreverを使用してマスタープロセスを管理する...
Dave Dopson

4
また、learnboostモジュールは、ノードv0.6.xにベイクされたバージョンのクラスターに取って代わられました(警告:APIサーフェスは異なります)
Dave Dopson

@broofaデフォルトのIPCと比較して、プロセス間で文字列/データ/配列を送信するだけで、RedisまたはMemcacheを使用するとしますか?どちらの方法が速いでしょうか?
NiCkニューマン

1
@ broofa、IPCには、JavaとCが実行できる実際の共有メモリと比較して大きなオーバーヘッドがあります。
パセリエ2017

@Pacerier True、ただし共有メモリは、単一のホストのコンテキストでスケーリングする方法の問題のみを解決し、多くのホスト間でスケーリングするために必要なマクロの問題に対処しません。つまり、クラウドで実行する方法です。
ブローファ2017年

20

クラスタモジュールを使用できます。これを確認してください。

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);
}

13

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

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


12

ノードJは、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.
}

完全なチュートリアルについては、この記事を確認してください


11

上記のように、クラスターはすべてのコアにわたってアプリをスケーリングおよび負荷分散します。

のようなものを追加する

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

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

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

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


3
PM2はプロダクション用途に最適です。監視ツールは、アプリのメモリ問題を解決するのに役立ちました。
mbokil 2016年

7

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

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


7

Spark2はSparkに基づいており、現在は保守されていません。クラスターはその後継であり、CPUコアごとに1つのワーカープロセスを生成したり、デッドワーカーを再生成したりするなど、いくつかの優れた機能を備えています。


元の質問とこれらの回答の多くは数か月前のものであり、ノードの移動が非常に速いため、クラスターについての説明を追加していただきありがとうございます。クラスターとその例を見ると、おかげで私(またはOP?)がNodeに求めているものとまったく同じに見えます。
リヤドカラ2011

5

ノードワーカーを使用して、メインプロセスから簡単な方法でプロセスを実行しています。公式の方法が出てくるのを待つ間、うまく機能しているようです。


1
ノードワーカーのexample.jsが実行できない理由、私のノードは0.3.3プレバージョンです
guilin桂林

5

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

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

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


5

クラスタモジュールは、あなたのマシンのすべてのコアを利用することができます。実際、2つのコマンドで、非常に人気のあるプロセスマネージャーpm2を使用してコードに手を加えることなく、これを利用できます。

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

4

所有しているCPUの数を検出するために使用できるosモジュールと組み合わせてクラスターモジュールを使用することにより、複数のコアでnode.jsアプリケーションを実行できます。

たとえばserver、バックエンドでシンプルなhttpサーバーを実行するモジュールがあり、いくつかの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();
}


0

unixソケットをリッスンするいくつかのスタンドアロンサーバーとしてWebサービスを設計することもできます。これにより、データ処理などの機能を別のプロセスにプッシュできます。

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

違いは、データ処理がポートでリッスンするノードWebサーバーとして書き込まれることです。

より複雑ですが、最終的にはマルチコア開発を行う必要があります。各Webリクエストに対して複数のコンポーネントを使用するマルチプロセスアーキテクチャ。


0

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

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


これらのサーバーにシングルコアCPUがない場合を除いて、CPU容量をすべて利用することはできません(他のことも実行している場合を除く)。
UpTheCreek 2012
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.