クラスタリングを使用して Node.js アプリケーションをスケーリングする方法
著者は寄付プログラムへの書き込みを選択しました。
序章
複数の CPU を搭載したシステムで Node.js プログラムを実行すると、デフォルトで単一の CPU のみを使用して実行するプロセスが作成されます。 Node.js は単一のスレッドを使用して JavaScript コードを実行するため、アプリケーションへのすべての要求は、単一の CPU で実行されるそのスレッドによって処理される必要があります。アプリケーションに CPU 集中型のタスクがある場合、オペレーティング システムはタスクが完了するまで単一の CPU を共有するようにスケジュールする必要があります。その結果、1 つのプロセスが大量のリクエストを受け取ると、そのプロセスが過負荷になり、パフォーマンスが低下する可能性があります。プロセスがクラッシュすると、ユーザーはアプリケーションにアクセスできなくなります。
解決策として、Node.js はラウンドロビン アルゴリズムを導入しました。 1 つのインスタンスがクラッシュした場合でも、実行中の残りのプロセスによってユーザーにサービスを提供できます。負荷が複数のプロセス間で均等に共有され、単一のインスタンスが圧倒されるのを防ぐため、アプリケーションのパフォーマンスが大幅に向上します。
このチュートリアルでは、4 つ以上の CPU を搭載したマシンで cluster
モジュールを使用して Node.js アプリケーションをスケーリングします。クラスタリングを使用しないアプリケーションを作成してから、クラスタリングを使用するようにアプリを変更します。 pm2
モジュールを使用して、アプリケーションを複数の CPU にスケーリングします。負荷テスト ツールを使用して、クラスタリングを使用するアプリと使用しないアプリのパフォーマンスを比較し、pm2
モジュールを評価します。
前提条件
このチュートリアルに従うには、次のものが必要です。
- 4 つ以上の CPU を搭載したシステム。
- Ubuntu 22.04 でリモート サーバーを使用している場合は、初期サーバー セットアップに従ってシステムをセットアップできます。
ステップ 1 - プロジェクト ディレクトリの設定
この手順では、プロジェクトのディレクトリを作成し、このチュートリアルで後でビルドするアプリケーションの依存関係をダウンロードします。ステップ 5 で。
まず、ディレクトリを作成します。
cluster_demo
または任意のディレクトリ名で呼び出すことができます。- mkdir cluster_demo
次に、ディレクトリに移動します。
- cd cluster_demo
次に、プロジェクトを初期化します。これにより、
package.json
ファイルも作成されます。- npm init -y
-y
オプションは、すべてのデフォルト オプションを受け入れるように NPM に指示します。コマンドを実行すると、次のような出力が生成されます。
OutputWrote to /home/sammy/cluster_demo/package.json: { "name": "cluster_demo", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "keywords": [], "author": "", "license": "ISC" }特定のプロジェクトに合わせた次のプロパティに注意してください。
name
: npm パッケージの名前version
: パッケージのバージョン番号。main
: プロジェクトのエントリ ポイント。
他のプロパティの詳細については、NPM のドキュメントの
package.json
セクションを参照してください。次に、任意のエディターで
package.json
ファイルを開きます (このチュートリアルではnano
を使用します)。- nano package.json
package.json
ファイルで、強調表示されたテキストを追加して、パッケージのインポート時に ES モジュールのサポートを有効にします。{ ... "author": "", "license": "ISC", "type": "module" }
CTRL+X
でファイルを保存して閉じます。次に、次のパッケージをダウンロードします。
express
: Node.js で Web アプリケーションを構築するためのフレームワークloadtest
: アプリへのトラフィックを生成してパフォーマンスを測定するのに役立つ負荷テスト ツールです。pm2
: アプリを複数の CPU に自動的にスケーリングするツール。
次のコマンドを実行して、Express パッケージをダウンロードします。
- npm install express
次に、コマンドを実行して
loadtest
およびpm2
パッケージをグローバルにダウンロードします。- npm install -g loadtest pm2
必要な依存関係をインストールしたので、クラスタリングを使用しないアプリケーションを作成します。
ステップ 2 — クラスターを使用せずにアプリケーションを作成する
この手順では、ユーザーがアクセスするたびに CPU を集中的に使用するタスクを開始する単一のルートを含むサンプル プログラムを作成します。このプログラムは
cluster
モジュールを使用しないため、1 つの CPU でアプリの 1 つのインスタンスを実行した場合のパフォーマンスへの影響にアクセスできます。チュートリアルの後半で、このアプローチをcluster
モジュールのパフォーマンスと比較します。nano
またはお気に入りのテキスト エディターを使用して、index.js
ファイルを作成します。- nano index.js
index.js
ファイルに次の行を追加して、Express をインポートしてインスタンス化します。import express from "express"; const port = 3000; const app = express(); console.log(`worker pid=${process.pid}`);
最初の行で、
express
パッケージをインポートします。 2 行目で、port
変数を、アプリケーションのサーバーがリッスンするポート3000
に設定します。次に、app
変数を Express のインスタンスに設定します。その後、組み込みのprocess
モジュールを使用して、アプリケーションのプロセスのプロセス ID をコンソールに記録します。次に、これらの行を追加してルート
/heavy
を定義します。これには CPU バウンド ループが含まれます。... app.get("/heavy", (req, res) => { let total = 0; for (let i = 0; i < 5_000_000; i++) { total++; } res.send(`The result of the CPU intensive task is ${total}\n`); });
/heavy
ルートでは、total
変数を 500 万回インクリメントするループを定義します。次に、res.send()
メソッドを使用して、total
変数の値を含む応答を送信します。 CPU バウンド タスクの例は任意ですが、複雑さを増すことなく CPU バウンド タスクを示しています。ルートに他の名前を使用することもできますが、このチュートリアルでは/heavy
を使用してパフォーマンスの高いタスクを示します。次に、Express モジュールの
listen()
メソッドを呼び出して、サーバーがポート3000
をリッスンし、port
変数に格納します。... app.listen(port, () => { console.log(`App listening on port ${port}`); });
完全なファイルは次のようになります。
import express from "express"; const port = 3000; const app = express(); console.log(`worker pid=${process.pid}`); app.get("/heavy", (req, res) => { let total = 0; for (let i = 0; i < 5_000_000; i++) { total++; } res.send(`The result of the CPU intensive task is ${total}\n`); }); app.listen(port, () => { console.log(`App listening on port ${port}`); });
コードの追加が完了したら、ファイルを保存して終了します。
node
コマンドを使用してファイルを実行します。- node index.js
コマンドを実行すると、出力は次のようになります。
Outputworker pid=11023 App listening on port 3000出力には、実行中のプロセスのプロセス ID と、サーバーがポート
3000
でリッスンしていることを確認するメッセージが示されます。アプリケーションが動作しているかどうかをテストするには、別のターミナルを開いて次のコマンドを実行します。
- curl http://localhost:3000/heavy
注: リモート サーバーでこのチュートリアルに従っている場合は、別のターミナルを開き、次のコマンドを入力します。
- ssh -L 3000:localhost:3000 your_non_root_user@your_server_ip
接続したら、次のコマンドを入力して、
curl
を使用してアプリにリクエストを送信します。- curl http://localhost:3000/heavy
出力は次のようになります。
OutputThe result of the CPU intensive task is 5000000出力は、CPU を集中的に使用する計算の結果を提供します。
この時点で、
CTRL+C
でサーバーを停止できます。node
コマンドでindex.js
ファイルを実行すると、オペレーティング システム (OS) によってプロセスが作成されます。プロセスは、実行中のプログラムに対してオペレーティング システムが作成する抽象化です。 OS はプログラムにメモリを割り当て、すべての OS プロセスを含むプロセス リストにエントリを作成します。そのエントリはプロセス ID です。次に、プログラムバイナリが特定され、プロセスに割り当てられたメモリにロードされます。そこから、実行を開始します。実行中、システム内の他のプロセスは認識されず、プロセスで発生したことは他のプロセスに影響しません。
複数の CPU を備えたサーバー上で実行されている Node.js アプリケーションに対して単一のプロセスがあるため、すべての着信要求を受信して処理します。この図では、すべての着信要求が単一の CPU で実行されているプロセスに送信され、他の CPU はアイドル状態のままです。
cluster
モジュールを使用せずにアプリを作成したので、次にcluster
モジュールを使用してアプリケーションをスケーリングし、複数の CPU を使用します。ステップ3-アプリケーションのクラスタリング
このステップでは、
cluster
モジュールを追加して同じプログラムの複数のインスタンスを作成し、より多くの負荷を処理してパフォーマンスを向上させます。cluster
モジュールでプロセスを実行すると、マシンの各 CPU で複数のプロセスを実行できます。この図では、リクエストはプライマリ プロセスのロード バランサーを通過し、ラウンド ロビン アルゴリズムを使用してプロセス間でリクエストを分散します。
cluster
モジュールを追加します。ターミナルで、primary.js
ファイルを作成します。- nano primary.js
primary.js
ファイルに、次の行を追加して依存関係をインポートします。import cluster from "cluster"; import os from "os"; import { dirname } from "path"; import { fileURLToPath } from "url"; const __dirname = dirname(fileURLToPath(import.meta.url));
最初の 2 行で、
cluster
およびos
モジュールをインポートします。次の 2 行では、dirname
とfileURLToPath
をインポートします。これを使用して、__dirname
変数値をディレクトリの絶対パスに設定します。index.js
ファイルが実行されています。__dirname
は ES モジュールの使用時には定義されておらず、デフォルトでは CommonJS モジュールでのみ定義されているため、これらのインポートが必要です。次に、
index.js
ファイルを参照する次のコードを追加します。... const cpuCount = os.cpus().length; console.log(`The total number of CPUs is ${cpuCount}`); console.log(`Primary pid=${process.pid}`); cluster.setupPrimary({ exec: __dirname + "/index.js", });
まず、
cpuCount
変数をマシンの CPU の数に設定します。これは 4 つ以上である必要があります。次に、コンソールに CPU の数を記録します。その後、すべてのリクエストを受信するプライマリ プロセスのプロセス ID をログに記録し、ロード バランサーを使用してそれらをワーカー プロセスに分散します。その後、各ワーカーで実行されるように、
cluster
モジュールのsetupPrimary()
メソッドを使用してindex.js
ファイルを参照します。プロセスが生成されました。次に、次のコードを追加してプロセスを作成します。
... for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on("exit", (worker, code, signal) => { console.log(`worker ${worker.process.pid} has been killed`); console.log("Starting another worker"); cluster.fork(); });
ループは
cpuCount
の値と同じ回数反復し、各反復中にcluster
モジュールのfork()
メソッドを呼び出します。cluster
モジュールのon()
メソッドを使用してexit
イベントをアタッチし、プロセスがexit
を発行したときにリッスンします。通常、これはプロセスが終了したときです。exit
イベントがトリガーされると、停止したワーカーのプロセス ID をログに記録し、fork()
メソッドを呼び出して新しいワーカー プロセスを作成し、停止したワーカー プロセスを置き換えます。プロセス。完全なコードは次のようになります。
import cluster from "cluster"; import os from "os"; import { dirname } from "path"; import { fileURLToPath } from "url"; const __dirname = dirname(fileURLToPath(import.meta.url)); const cpuCount = os.cpus().length; console.log(`The total number of CPUs is ${cpuCount}`); console.log(`Primary pid=${process.pid}`); cluster.setupPrimary({ exec: __dirname + "/index.js", }); for (let i = 0; i < cpuCount; i++) { cluster.fork(); } cluster.on("exit", (worker, code, signal) => { console.log(`worker ${worker.process.pid} has been killed`); console.log("Starting another worker"); cluster.fork(); });
行の追加が完了したら、ファイルを保存して終了します。
次に、ファイルを実行します。
- node primary.js
出力は次のようになります (プロセス ID と情報の順序は異なる場合があります)。
OutputThe total number of CPUs is 4 Primary pid=7341 worker pid=7353 worker pid=7354 worker pid=7360 App listening on port 3000 App listening on port 3000 App listening on port 3000 worker pid=7352 App listening on port 3000出力には、4 つの CPU、ロード バランサーを含む 1 つのプライマリ プロセス、およびポート
3000
でリッスンしている 4 つのワーカー プロセスが示されます。次に、2 番目のターミナルに戻り、
/heavy
ルートにリクエストを送信します。- curl http://localhost:3000/heavy
出力は、プログラムが機能していることを確認します。
OutputThe result of the CPU intensive task is 5000000これでサーバーを停止できます。
この時点で、マシンのすべての CPU で 4 つのプロセスが実行されます。
アプリケーションにクラスタリングを追加すると、
cluster
モジュールを使用した場合とcluster
モジュールを使用しない場合のプログラムのパフォーマンスを比較できます。ステップ 4 — 負荷テスト ツールを使用したパフォーマンスの比較
このステップでは、
loadtest
パッケージを使用して、作成した 2 つのプログラムに対するトラフィックを生成します。cluster
モジュールを使用するprimary.js
プログラムのパフォーマンスと、使用しないindex.js
プログラムのパフォーマンスを比較します。クラスタリング。cluster
モジュールを使用するプログラムは、クラスタリングを使用しないプログラムよりも高速に実行され、特定の時間内により多くのリクエストを処理できることがわかります。まず、
cluster
モジュールを使用せず、単一のインスタンスでのみ実行されるindex.js
ファイルのパフォーマンスを測定します。最初のターミナルで、
index.js
ファイルを実行してサーバーを起動します。- node index.js
アプリが実行されているという出力が表示されます。
Outputworker pid=7731 App listening on port 3000次に、2 番目のターミナルに戻り、
loadtest
パッケージを使用してサーバーにリクエストを送信します。- loadtest -n 1200 -c 200 -k http://localhost:3000/heavy
-n
オプションは、パッケージが送信する必要があるリクエストの数を受け入れます。これは、ここでは1200
リクエストです。-c
オプションは、サーバーに同時に送信する必要があるリクエストの数を受け入れます。リクエストが送信されると、パッケージは次のような出力を返します。
OutputRequests: 0 (0%), requests per second: 0, mean latency: 0 ms Requests: 430 (36%), requests per second: 87, mean latency: 1815.1 ms Requests: 879 (73%), requests per second: 90, mean latency: 2230.5 ms Target URL: http://localhost:3000/heavy Max requests: 1200 Concurrency level: 200 Agent: keepalive Completed requests: 1200 Total errors: 0 Total time: 13.712728601 s Requests per second: 88 Mean latency: 2085.1 ms Percentage of the requests served within a certain time 50% 2234 ms 90% 2340 ms 95% 2385 ms 99% 2406 ms 100% 2413 ms (longest request)この出力から、次のメトリックに注意してください。
Total time
は、すべてのリクエストが処理されるまでにかかった時間を測定します。この出力では、1200
のすべてのリクエストを処理するのに 13 秒強かかりました。1 秒あたりのリクエスト数
は、サーバーが 1 秒あたりに処理できるリクエスト数を測定します。この出力では、サーバーは 1 秒あたり88
のリクエストを処理しています。平均レイテンシ
は、リクエストを送信してレスポンスを取得するまでにかかった時間を測定します。サンプル出力では、2085.1 ミリ秒
です。
これらのメトリックは、ネットワークまたはプロセッサの速度によって異なりますが、これらの例に近いものになります。
index.js
ファイルのパフォーマンスを測定したので、サーバーを停止できます。次に、
cluster
モジュールを使用するprimary.js
ファイルのパフォーマンスを測定します。これを行うには、最初のターミナルに戻り、
primary.js
ファイルを再実行します。- node primary.js
以前と同じ情報を含む応答を受け取ります。
OutputThe total number of CPUs is 4 Primary pid=7841 worker pid=7852 App listening on port 3000 worker pid=7854 App listening on port 3000 worker pid=7853 worker pid=7860 App listening on port 3000 App listening on port 30002 番目のターミナルで、
loadtest
コマンドを再度実行します。- loadtest -n 1200 -c 200 -k http://localhost:3000/heavy
完了すると、同様の出力が表示されます (システムの CPU の数によって異なる場合があります)。
OutputRequests: 0 (0%), requests per second: 0, mean latency: 0 ms Target URL: http://localhost:3000/heavy Max requests: 1200 Concurrency level: 200 Agent: keepalive Completed requests: 1200 Total errors: 0 Total time: 3.412741962 s Requests per second: 352 Mean latency: 514.2 ms Percentage of the requests served within a certain time 50% 194 ms 90% 2521 ms 95% 2699 ms 99% 2710 ms 100% 2759 ms (longest request)cluster
モジュールで実行されているprimary.js
アプリの出力は、合計時間が 13 秒から 3 秒に短縮されていることを示しています。 t クラスタリングを使用します。サーバーが 1 秒あたりに処理できるリクエストの数は、以前の88
から352
に 3 倍になりました。これは、サーバーに大きな負荷がかかる可能性があることを意味します。もう 1 つの重要な指標は平均レイテンシです。これは2085.1 ms
から514.2 ms
に大幅に低下しています。この応答により、スケーリングが機能し、アプリケーションが遅延なく短時間でより多くの要求を処理できることが確認されます。マシンをアップグレードして CPU を増やすと、アプリは自動的に CPU の数に合わせてスケーリングし、パフォーマンスをさらに向上させます。
ネットワークとプロセッサの速度によって、ターミナル出力のメトリックが異なることに注意してください。合計時間と平均待ち時間が大幅に減少し、合計時間が急速に増加します。
比較を行い、
cluster
モジュールを使用した方がアプリのパフォーマンスが向上することがわかったので、サーバーを停止できます。次のステップでは、cluster
モジュールの代わりにpm2
を使用します。ステップ 5 — クラスタリングに pm2 を使用する
これまで、
cluster
モジュールを使用して、マシンの CPU の数に応じてワーカー プロセスを作成しました。また、ワーカー プロセスが終了したときに再起動する機能も追加しました。このステップでは、cluster
モジュールに基づいて構築されたpm2
プロセス マネージャーを使用して、アプリのスケーリングを自動化するための代替手段を設定します。このプロセス マネージャーにはロード バランサーが含まれており、マシン上の CPU と同じ数のワーカー プロセスを自動的に作成できます。また、プロセスを監視したり、ワーカー プロセスが停止した場合に新しいワーカー プロセスを自動的に生成したりすることもできます。これを使用するには、スケールする必要があるファイル (このチュートリアルでは
index.js
ファイル) を含むpm2
パッケージを実行する必要があります。最初のターミナルで、次のコマンドを使用して
pm2
クラスターを開始します。- pm2 start index.js -i 0
-i
オプションは、pm2
で作成するワーカー プロセスの数を受け入れます。引数0
を渡すと、pm2
はマシンの CPU と同じ数のワーカー プロセスを自動的に作成します。コマンドを実行すると、
pm2
はワーカー プロセスの詳細を表示します。Output... [PM2] Spawning PM2 daemon with pm2_home=/home/sammy/.pm2 [PM2] PM2 Successfully daemonized [PM2] Starting /home/sammy/cluster_demo/index.js in cluster_mode (0 instance) [PM2] Done. ┌─────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │ ├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 0 │ index │ default │ 1.0.0 │ cluster │ 7932 │ 0s │ 0 │ online │ 0% │ 54.5mb │ nod… │ disabled │ │ 1 │ index │ default │ 1.0.0 │ cluster │ 7939 │ 0s │ 0 │ online │ 0% │ 50.9mb │ nod… │ disabled │ │ 2 │ index │ default │ 1.0.0 │ cluster │ 7946 │ 0s │ 0 │ online │ 0% │ 51.3mb │ nod… │ disabled │ │ 3 │ index │ default │ 1.0.0 │ cluster │ 7953 │ 0s │ 0 │ online │ 0% │ 47.4mb │ nod… │ disabled │ └─────┴──────────┴─────────────┴─────────┴─────────┴──────────┴────────┴──────┴───────────┴──────────┴──────────┴──────────┴──────────┘テーブルには、各ワーカーのプロセス ID、ステータス、CPU 使用率、およびメモリ消費量が含まれており、プロセスの動作を理解するために使用できます。
pm2
でクラスターを開始すると、パッケージはバックグラウンドで実行され、システムを再起動しても自動的に再起動します。ワーカー プロセスからログを読み取る場合は、次のコマンドを使用できます。
- pm2 logs
ログの出力を受け取ります。
Output[TAILING] Tailing last 15 lines for [all] processes (change the value with --lines option) /home/sammy/.pm2/pm2.log last 15 lines: ... PM2 | 2022-12-25T17:48:37: PM2 log: App [index:3] starting in -cluster mode- PM2 | 2022-12-25T17:48:37: PM2 log: App [index:3] online /home/sammy/.pm2/logs/index-error.log last 15 lines: /home/sammy/.pm2/logs/index-out.log last 15 lines: 0|index | worker pid=7932 0|index | App listening on port 3000 0|index | worker pid=7953 0|index | App listening on port 3000 0|index | worker pid=7946 0|index | worker pid=7939 0|index | App listening on port 3000 0|index | App listening on port 3000最後の 8 行で、ログはプロセス ID とポート番号
3000
を含む、実行中の 4 つのワーカー プロセスのそれぞれからの出力を提供します。この出力は、すべてのプロセスが実行中であることを確認します。次のコマンドを使用して、プロセスのステータスを確認することもできます。
- pm2 ls
出力は次の表と一致します。
Output┌─────┬──────────┬─────────────┬─────────┬─────────┬──────────┬────────┬──────┬───────────┬──────────┬──────────┬──────────┬──────────┐ │ id │ name │ namespace │ version │ mode │ pid │ uptime │ ↺ │ status │ cpu │ mem │ user │ watching │ ├─────┼──────────┼─────────────┼─────────┼─────────┼──────────┼────────┼──────┼───────────┼──────────┼──────────┼──────────┼──────────┤ │ 0 │ index │ default │ 1.0.0 │ cluster │ 7932 │ 5m │ 0 │ online │ 0% │ 56.6mb │ nod… │ disabled │ │ 1 │ index │ default │ 1.0.0 │ cluster │ 7939 │ 5m │ 0 │ online │ 0% │ 55.7mb │ nod… │ disabled │ │ 2 │ index │ default │ 1.0.0 │ cluster │ 7946 │ 5m │ 0 │ online │ 0% │ 56.5mb │ nod… │ disabled │ │ 3 │ index │ default │ 1.0.0 │ cluster │ 7953 │ 5m │ 0 │ online │ 0% │ 55.9mb │ nod… │ disabled │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘クラスターが実行されているので、同じターミナルで次のコマンドを入力して、そのパフォーマンスをテストします。
- loadtest -n 1200 -c 200 -k http://localhost:3000/heavy
出力は次のものとほぼ一致します。
OutputRequests: 0 (0%), requests per second: 0, mean latency: 0 ms Target URL: http://localhost:3000/heavy Max requests: 1200 Concurrency level: 200 Agent: keepalive Completed requests: 1200 Total errors: 0 Total time: 3.771868785 s Requests per second: 318 Mean latency: 574.4 ms Percentage of the requests served within a certain time 50% 216 ms 90% 2859 ms 95% 3016 ms 99% 3028 ms 100% 3084 ms (longest request)Total time
、Requests per second
、およびMean latency
は、cluster
を使用したときに生成された指標に近くなっていますモジュール。この配置は、pm2
スケーリングが同様に機能することを示しています。pm2
でワークフローを改善するために、構成ファイルを生成してアプリケーションの構成設定を渡すことができます。このアプローチにより、オプションを渡さずにクラスターを開始または再起動できます。構成ファイルを使用するには、現在のクラスターを削除します。
- pm2 delete index.js
なくなったという応答を受け取ります。
Output[PM2] Applying action deleteProcessId on app [index.js](ids: [ 0, 1, 2, 3 ]) [PM2] [index](2) ✓ [PM2] [index](1) ✓ [PM2] [index](0) ✓ [PM2] [index](3) ✓ ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘次に、構成ファイルを生成します。
- pm2 ecosystem
出力は、ファイルが生成されたことを確認します。
OutputFile /home/sammy/cluster_demo/ecosystem.config.js generated.js
の名前を.cjs
に変更して、ES モジュールのサポートを有効にします。- mv ecosystem.config.js ecosystem.config.cjs
エディターを使用して、構成ファイルを開きます。
- nano ecosystem.config.cjs
ecosystem.config.cjs
ファイルに、以下の強調表示されたコードを追加します。module.exports = { apps : [{ script: 'index.js', watch: '.', name: "cluster_app", instances: 0, exec_mode: "cluster", }, { script: './service-worker/', watch: ['./service-worker'] }], deploy : { production : { user : 'SSH_USERNAME', host : 'SSH_HOSTMACHINE', ref : 'origin/master', repo : 'GIT_REPOSITORY', path : 'DESTINATION_PATH', 'pre-deploy-local': '', 'post-deploy' : 'npm install && pm2 reload ecosystem.config.cjs --env production', 'pre-setup': '' } } };
script
オプションは、pm2
パッケージが生成する各プロセスで実行されるファイルを受け入れます。name
プロパティは、クラスターを識別できる任意の名前を受け入れます。これは、停止、再起動、またはその他のアクションを実行する必要がある場合に役立ちます。instances
プロパティは、必要なインスタンスの数を受け入れます。instances
を0
に設定すると、pm2
は CPU と同じ数のプロセスを生成します。exec_mode
はcluster
オプションを受け入れます。これはpm2
をクラスターで実行するように指示します。終了したら、ファイルを保存して閉じます。
クラスターを開始するには、次のコマンドを実行します。
- pm2 start ecosystem.config.cjs
次の応答が返されます。
Output[PM2][WARN] Applications cluster_app, service-worker not running, starting... [PM2][ERROR] Error: Script not found: /home/node-user/cluster_demo/service-worker [PM2] App [cluster_app] launched (4 instances)最後の行は、
4
個のプロセスが実行されていることを確認します。このチュートリアルではservice-worker
スクリプトを作成していないため、service-worker
が見つからないというエラーは無視できます。クラスタが動作していることを確認するには、ステータスを確認します。
- pm2 ls
4 つのプロセスが実行されていることを確認する応答を受け取ります。
Output┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ cluster_app │ cluster │ 0 │ online │ 0% │ 56.9mb │ │ 1 │ cluster_app │ cluster │ 0 │ online │ 0% │ 57.6mb │ │ 2 │ cluster_app │ cluster │ 0 │ online │ 0% │ 55.9mb │ │ 3 │ cluster_app │ cluster │ 0 │ online │ 0% │ 55.9mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘クラスターを再起動する場合は、
ecosystem.config.cjs
ファイルで定義したアプリ名を使用できます。この場合はcluster_app
です:- pm2 restart cluster_app
クラスターが再起動します。
OutputUse --update-env to update environment variables [PM2] Applying action restartProcessId on app [cluster_app](ids: [ 0, 1, 2, 3 ]) [PM2] [cluster_app](0) ✓ [PM2] [cluster_app](1) ✓ [PM2] [cluster_app](2) ✓ [PM2] [cluster_app](3) ✓ ┌────┬────────────────────┬──────────┬──────┬───────────┬──────────┬──────────┐ │ id │ name │ mode │ ↺ │ status │ cpu │ memory │ ├────┼────────────────────┼──────────┼──────┼───────────┼──────────┼──────────┤ │ 0 │ cluster_app │ cluster │ 1 │ online │ 0% │ 48.0mb │ │ 1 │ cluster_app │ cluster │ 1 │ online │ 0% │ 47.9mb │ │ 2 │ cluster_app │ cluster │ 1 │ online │ 0% │ 38.8mb │ │ 3 │ cluster_app │ cluster │ 1 │ online │ 0% │ 31.5mb │ └────┴────────────────────┴──────────┴──────┴───────────┴──────────┴──────────┘クラスターの管理を続行するには、次のコマンドを実行できます。
Command Description pm2 start app_name
Starts the cluster pm2 restart app_name
Kills the cluster and starts it again pm2 reload app_name
Restarts the cluster without downtime pm2 stop app_name
Stops the cluster pm2 delete app_name
Deletes the cluster pm2
モジュールとcluster
モジュールを使用してアプリケーションをスケーリングできるようになりました。結論
このチュートリアルでは、
cluster
モジュールを使用してアプリケーションをスケーリングしました。まず、cluster
モジュールを使用しないプログラムを作成しました。次に、cluster
モジュールを使用してアプリをマシン上の複数の CPU にスケーリングするプログラムを作成しました。その後、cluster
モジュールを使用するアプリと使用しないアプリのパフォーマンスを比較しました。最後に、cluster
モジュールの代わりにpm2
パッケージを使用して、アプリを複数の CPU にスケーリングしました。さらに進むには、
cluster
モジュールのドキュメント ページにアクセスして、モジュールの詳細を確認してください。pm2
を引き続き使用する場合は、Ubuntu 22.04 で本番用に Node.js アプリケーションをセットアップする方法を参照してください。Node.js には、Node.js と BullMQ で非同期タスクを処理する方法も同梱されています。