Search code examples
node.jsserverportscalabilitypm2

How ports work when scaling server using nodejs pm2


I'm learning how to scale servers in a little sandbox I've setup. Here's the very simple code:

'use strict';

const express = require('express');
const bodyParser = require('body-parser');
const app = express();

const instanceId = parseInt(Math.random() * 1000);

//Allow all requests from all domains & localhost
app.all('/*', function(req, res, next) {
  res.header("Access-Control-Allow-Origin", "*");
  res.header("Access-Control-Allow-Headers", "X-Requested-With, Content-Type, Accept");
  res.header("Access-Control-Allow-Methods", "POST, GET");
  next();
});

app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}));

app.get('/', function(req, res) {
  console.log(`[${new Date()}] ${req.method} ${req.originalUrl} from ${req.ip} at ${instanceId}`);
  res.send(`received at ${Date.now()} from ${instanceId}`);
});

app.listen(6069);

Nothing crazy, just spits out the date and the instance the request was received at.

The pm2 docs for scaling a nodejs server advised me to run:

pm2 start server.js -i 5

which worked perfectly fine. Here's an example output when I stress tested it using npm module loadtest:

server-0 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 847
server-1 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 261
server-3 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 328
server-2 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 163
server-4 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 351
server-0 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 847
server-3 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 328
server-1 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 261
server-2 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 163
server-4 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 351
server-0 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 847
server-3 [Sun Aug 07 2016 00:13:53 GMT-0400 (EDT)] GET / from ::ffff:127.0.0.1 at 328

Here's my question. Why didn't node throw an error that port 6069 is in use? Multiple servers are attempting to use the port—yet there's no complaining. Why?


Solution

  • PM2 creates it's own "embedded load-balancer which uses Round-robin algorithm to better distribute load among the workers". So it basically wraps a load-balancer around your app and proxies the request to each node it creates.

    When using Round-robin scheduling policy, the master accepts() all incoming connections and sends the TCP handle for that particular connection to the chosen worker (via IPC).