Node.js興味深いですが、何かが欠けているに違いありません。Node.js は単一のプロセスとスレッドでのみ実行されるように調整されているのではないですか?
では、マルチコア CPU とマルチ CPU サーバーではどのように拡張するのでしょうか。結局のところ、シングル スレッド サーバーをできるだけ高速にすることは素晴らしいことですが、高負荷の場合は複数の CPU を使用する必要があります。アプリケーションを高速化する場合も同様です。現在では、複数の CPU を使用してタスクを並列化する方法のようです。
Node.js はこの図にどのように当てはまるのでしょうか? 何らかの方法で複数のインスタンスを分散するというアイデアでしょうか?
ベストアンサー1
[この投稿は 2012-09-02 時点の最新です (上記より新しいです)。 ]
Node.js はマルチコアマシン上で確実にスケーリングします。
はい、Node.js はプロセスごとに 1 つのスレッドです。これは非常に意図的な設計上の決定であり、ロック セマンティクスに対処する必要がありません。これに同意しない場合は、マルチスレッド コードのデバッグがいかに難しいかをまだ理解していない可能性があります。Node.js のプロセス モデルと、なぜこのように動作するのか (そしてなぜマルチスレッドをサポートしないのか) の詳細な説明については、以下をお読みください。私の他の投稿。
では、16 コア ボックスをどのように活用すればよいのでしょうか?
ふたつのやり方:
- イメージエンコードのような大規模で負荷の高い計算タスクの場合、Node.js は子プロセスを起動したり、追加のワーカープロセスにメッセージを送信したりできます。この設計では、1 つのスレッドでイベントのフローを管理し、N 個のプロセスで負荷の高い計算タスクを実行して、他の 15 個の CPU を消費します。
- Web サービスのスループットを拡張するには、1 つのボックスで複数の Node.js サーバー (コアごとに 1 つ) を実行し、それらの間でリクエスト トラフィックを分割する必要があります。これにより、優れた CPU アフィニティが提供され、コア数に応じてスループットがほぼ直線的に拡張されます。
ウェブサービスのスループットのスケーリング
v6.0.X以降、Node.jsにはクラスターモジュールすぐに使えるので、単一のポートでリッスンできる複数のノードワーカーを簡単に設定できます。これは、ネプ。
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.Server(function(req, res) { ... }).listen(8000);
}
ワーカーは新しい接続を受け入れるために競争し、最も負荷の少ないプロセスが勝つ可能性が最も高くなります。これは非常にうまく機能し、マルチコア ボックスでスループットをかなりうまくスケールアップできます。
複数のコアを気にするほどの負荷がある場合は、さらにいくつかのことを行う必要があります。
Node.jsサービスをWebプロキシの背後で実行するには、エンギンクスまたはアパッチ- 接続スロットリング (過負荷状態によってボックスが完全にダウンすることを望まない場合)、URL の書き換え、静的コンテンツの提供、および他のサブサービスのプロキシを実行できるもの。
ワーカー プロセスを定期的にリサイクルします。長時間実行されるプロセスの場合、小さなメモリ リークでも最終的には蓄積されていきます。
ログ収集/監視の設定
追記: 別の投稿 (この記事の執筆時点ではトップの投稿) のコメントに、アーロンとクリストファーの間で議論が交わされています。それについていくつかコメントします。
- 共有ソケット モデルは、複数のプロセスが単一のポートをリッスンし、新しい接続を受け入れるために競合できるようにするのに最適です。概念的には、各プロセスが 1 つの接続のみを受け入れて終了するという重要な注意点を付帯して、プリフォークされた Apache がこれを実行すると考えることができます。Apache の効率低下は、新しいプロセスをフォークするオーバーヘッドによるもので、ソケット操作とは関係ありません。
- Node.js の場合、N 個のワーカーを 1 つのソケットで競合させるのは非常に合理的なソリューションです。別の方法としては、Nginx のようなオンボックス フロントエンドを設定し、そのプロキシ トラフィックを個々のワーカーに渡し、ワーカーを交互に切り替えて新しい接続を割り当てるという方法があります。この 2 つのソリューションのパフォーマンス特性は非常に似ています。また、上で述べたように、いずれにしてもノード サービスのフロントに Nginx (または代替手段) を配置することが必要になるため、ここでの選択肢は次の 2 つです。
共有ポート: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) ...}
個々のポートを設定することには、おそらくいくつかの利点(プロセス間の結合が少なくなる可能性、より洗練された負荷分散の決定など)がありますが、設定には間違いなくより多くの作業が必要であり、組み込みのクラスター モジュールは、ほとんどの人にとって機能する複雑さの少ない代替手段です。