LoginSignup
57
48

More than 5 years have passed since last update.

pm2のforkモードで動的にCPUと同じ数のhttpサーバを起動する

Posted at

目的

pm2のclusterモードは便利ですが、リクエストのロードバランスはNginxなどで行いたい場合があります。
pm2のforkモードでCPUの数に応じて動的にサーバプロセスを立ちあげる方法について調べました。

clusterモードでは

pm2のclusterモード(Node.jsのclusterモジュール)はportを割り当てられるのはマスタープロセスだけなので、
以下の用にinstances=0としてマスタープロセス用の設定を書けば、
portを割り当てられたマスタープロセス1個と、実際にリクエストを処理するワーカープロセスがCPU数起動します。

process.json
{
  "name": "pm2sample",
  "script": "server.js",
  "exec_mode": "cluster_mode",
  "instances": 0
}
server.js
var http = require('http');
var port = 8080;
http.createServer(function(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/plain'
  });
  res.end("PID:" + process.pid + ' pm2sample app.\n');
}).listen(port);
CPUの数だけワーカープロセスが立ち上がる
$ pm2 start process.json

forkモードの問題点

単純にexec_mode=forkと修正して起動すると、同じportを割り当てられたサーバプロセスを複数起動しようとして最初のプロセス以外起動しません。

process.json
{
  "name": "pm2sample",
  "script": "server.js",
  "exec_mode": "fork",
  "instances": 0
}

pm2のログを見てみると最初のプロセスは起動できていますが、それ以外のプロセスはエラーが発生しています。

~/.pm2/logs/pm2sample-error-N.log
events.js:85
      throw er; // Unhandled 'error' event
            ^
Error: listen EADDRINUSE
    at exports._errnoException (util.js:746:11)
    at Server._listen2 (net.js:1156:14)
    at listen (net.js:1182:10)
    at Server.listen (net.js:1267:5)
    at Object.<anonymous> (/Users/duck1218/workspace/github.com/geekduck/pm2sample/server.js:8:4)
    at Module._compile (module.js:460:26)
    at Object.Module._extensions..js (module.js:478:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:501:10)
〜省略〜

設定ファイルに個別に全てのプロセス用の設定を書いても良いですが、
本番環境と開発環境でCPUの数が違う場合などで問題が起きます。

解決方法

以下のissueに書いてあるとおり、環境変数NODE_APP_INSTANCEを使って割り当てるportを動的に決定しましょう。
NODE_APP_INSTANCEは0からはじまる連番が渡されます。
Pass instance id to app as environment variable

server.jsを修正してNODE_APP_INSTANCEを使用してportを設定します。

server.js
var http = require('http');
var port = 8080 + parseInt(process.env.NODE_APP_INSTANCE || 0); // CPUが4個の場合port8080〜8083のサーバが起動する
http.createServer(function(req, res) {
  res.writeHead(200, {
    'Content-Type': 'text/plain'
  });
  res.end("PID:" + process.pid + ' pm2sample app.\n');
}).listen(port);

CPUが4つの環境ではlocalhost:8080, localhost:8081, localhost:8082, localhost:8083でサーバが起動します。

あとはNginxでロードバランスしてあげれば完璧です!

nginx.conf
upstream io_nodes {
  ip_hash;
  server 127.0.0.1:8080;
  server 127.0.0.1:8081;
  server 127.0.0.1:8082;
  server 127.0.0.1:8082;
}

サンプルコード:https://github.com/geekduck/pm2sample

57
48
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
57
48