Node.js Clusterの基本概念を理解する
Grace Collins
Solutions Engineer · Leapcell

はじめに
PM2を使用してNode.jsプロセスを管理している場合、クラスターモードがサポートされていることに気づいたかもしれません。このモードでは、Node.jsが複数のプロセスを作成できます。クラスターモードのインスタンス数をmaxに設定すると、PM2はサーバーで使用可能なCPUコア数に対応する数のNodeプロセスを自動的に作成します。
PM2は、Node.jsのClusterモジュールを利用してこれを実現します。このモジュールは、Node.jsのシングルスレッドという性質に対処し、従来は複数のCPUコアを活用する能力を制限していました。しかし、Clusterモジュールは内部でどのように機能するのでしょうか?プロセスは互いにどのように通信するのでしょうか?複数のプロセスが同じポートをリッスンするにはどうすればよいのでしょうか?また、Node.jsはこれらのプロセスにリクエストをどのように分散するのでしょうか?これらの質問に興味がある場合は、読み進めてください。
基本原則
Node.jsのワーカープロセスは、child_process.fork()
メソッドを使用して作成されます。これは、1つの親プロセスと複数の子プロセスがあることを意味します。コードは通常、次のようになります。
const cluster = require('cluster'); const os = require('os'); if (cluster.isMaster) { for (let i = 0, n = os.cpus().length; i < n; i++) { cluster.fork(); } } else { // アプリケーションを起動します }
オペレーティングシステムを学んだことがあるなら、fork()
システムコールにおそらく精通しているでしょう。呼び出し元のプロセスは親であり、新しく作成されたプロセスは子です。これらの子プロセスは、親と同じデータセグメントとスタックを共有しますが、物理メモリ空間は必ずしも共有されません。Node.js Clusterでは、マスタープロセスがポートをリッスンし、受信リクエストをワーカープロセスに分散します。これには、プロセス間通信(IPC)、ロードバランシング戦略、およびマルチプロセスポートリスニングという3つの中核的なトピックに対処することが含まれます。
プロセス間通信(IPC)
マスタープロセスは、process.fork()
を使用して子プロセスを作成します。これらのプロセス間の通信は、IPCチャネルを介して処理されます。オペレーティングシステムは、プロセス間通信のためのいくつかのメカニズムを提供します。以下に例を挙げます。
-
共有メモリ 複数のプロセスが単一のメモリ空間を共有し、多くの場合、同期と相互排他のためにセマフォで管理されます。
-
メッセージパッシング プロセスはメッセージを送受信することでデータを交換します。
-
セマフォ セマフォは、システムによって割り当てられたステータス値です。制御が不足しているプロセスは、特定のチェックポイントで強制的に停止され、続行するための信号を待ちます。バイナリ値(0または1)に制限されている場合、このメカニズムは「mutex」(相互排他ロック)として知られています。
-
パイプ パイプは2つのプロセスを接続し、あるプロセスの出力を別のプロセスの入力として機能させることができます。これは、
pipe
システムコールを使用して作成できます。シェルスクリプトの|
コマンドは、このメカニズムの一般的な例です。
Node.jsは、親プロセスと子プロセス間の通信にイベントベースのメカニズムを使用します。TCPサーバーハンドルを子プロセスに送信する親プロセスの例を次に示します。
const subprocess = require('child_process').fork('subprocess.js'); // サーバーを作成し、そのハンドルを送信します。 const server = require('net').createServer(); server.on('connection', (socket) => { socket.end('親プロセスによって処理されます'); }); server.listen(1337, () => { subprocess.send('server', server); }); process.on('message', (m, server) => { if (m === 'server') { server.on('connection', (socket) => { socket.end('子プロセスによって処理されます'); }); } });
ロードバランシング戦略
前述のように、すべてのリクエストはマスタープロセスによって分散されます。サーバーの負荷がワーカープロセス間で均等に分散されるようにするには、ロードバランシング戦略が必要です。Node.jsは、デフォルトでラウンドロビンアルゴリズムを使用します。
ラウンドロビン
ラウンドロビン方式は、Nginxでも採用されている一般的なロードバランシングアルゴリズムです。これは、受信リクエストを各プロセスに順番に分散することで機能します。最初のプロセスから開始し、最後のプロセスに到達した後、ループバックします。ただし、この方法は、すべてのプロセスで処理能力が等しいことを前提としています。リクエストの処理時間が大幅に異なるシナリオでは、負荷の不均衡が発生する可能性があります。
これに対処するために、Nginxは**Weighted Round-Robin(WRR)**を使用することがよくあります。この場合、サーバーには異なる重みが割り当てられます。重みがゼロになるまで、最も高い重みを持つサーバーが選択され、その時点で新しい重みシーケンスに基づいてサイクルが再開されます。
Node.jsでロードバランシング戦略を調整するには、NODE_CLUSTER_SCHED_POLICY
環境変数を設定するか、cluster.setupMaster(options)
を使用して構成します。マルチマシンクラスター用のNginxと、シングルマシンマルチプロセスバランシング用のNode.js Clusterを組み合わせるのが一般的なアプローチです。
マルチプロセスポートリスニング
Node.jsの初期バージョンでは、同じポートをリッスンしている複数のプロセスが着信接続を競合し、負荷分散が不均一になっていました。これは、後にラウンドロビン戦略で解決されました。現在のアプローチは、次のとおりです。
- マスタープロセスはソケットを作成し、アドレスにバインドして、リスニングを開始します。
- ソケットのファイル記述子(fd)は、ワーカープロセスには渡されません。
- マスタープロセスが新しい接続を受け入れると、どのワーカープロセスが接続を処理する必要があるかを判断し、それに応じて転送します。
基本的に、マスタープロセスはポートをリッスンし、定義された戦略(たとえば、ラウンドロビン)を使用してワーカープロセスに接続を分散します。この設計により、ワーカー間の競合が解消されますが、マスタープロセスが非常に安定している必要があります。
結論
PM2のクラスターモードをエントリポイントとして、この記事では、マルチプロセスアプリケーションを実装するためのNode.jsのClusterモジュールの背後にある基本原則を調べました。プロセス間通信、ロードバランシング、およびマルチプロセスポートリスニングという3つの重要な側面に焦点を当てました。
Clusterモジュールを調べることで、多くの基本原則とアルゴリズムが普遍的であることがわかります。たとえば、ラウンドロビンアルゴリズムは、オペレーティングシステムのプロセススケジューリングとサーバーのロードバランシングの両方で使用されます。マスターワーカーアーキテクチャは、Nginxのマルチプロセス設計に似ています。同様に、セマフォやパイプなどのメカニズムは、さまざまなプログラミングパラダイムでユビキタスです。
新しいテクノロジーが継続的に出現していますが、その基盤は一貫しています。これらのコアコンセプトを理解することで、自信を持って新しい課題を推測し、適応することができます。
Node.jsプロジェクトをクラウドにデプロするために、Leapcellをお選びください。
Leapcellは、Webホスティング、非同期タスク、およびRedis向けの次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、またはRustで開発します。
無制限のプロジェクトを無料でデプロイ
- 使用量に対してのみ支払い、リクエストも課金もありません。
比類のないコスト効率
- アイドル料金なしの従量課金制。
- 例:25ドルで、平均応答時間60ミリ秒で694万リクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOps統合。
- 実用的な洞察のためのリアルタイムのメトリックとロギング。
簡単なスケーラビリティと高いパフォーマンス
- 簡単な高並行性を処理するための自動スケーリング。
- 運用上のオーバーヘッドはゼロです。構築に集中してください。
ドキュメントで詳細をご覧ください。
Xでフォローしてください:@LeapcellHQ