Nodejs cluster for multi cores computer.

2 months ago

By default NodeJS will only use 1 core of your processor (cpu). So if you on 4 cores computer you only using 1. 

Solution

To take advantage of multi-core system we use cluster.

What cluster does is it create copies of your app. So if you on 4 cores you will have 4 copy of your app. Which mean you can handle 4 time the traffic capacity.

Usage.

We need to check if you have multi-core machine.

console.log(require('os').cpus().length) //4

1. Best way: use pm2 coz it keep your code untouch

pm2 start bin/www -i max

- max mean use all core available.
- if you already have pm2 run just delete it and run above command.

your pm2 status now will be cluster instead of fork

Localhost

┌──────┬────┬───────┬─────────┬────────┬─────┬────────┬───────────┐
│ Name │ id │ mode  │ status  │ ↺      │ cpu │ memory │
├──────┼────┼───────┼─────────┼────────┼─────┼────────┼───────────┤
│ www  │ 0  │ 0.0.1 │ cluster │ online │ 2   │ 0%     │ 41.5 MB   │
│ www  │ 1  │ 0.0.1 │ cluster │ online │ 2   │ 0%     │ 42.0 MB   │
│ www  │ 2  │ 0.0.1 │ cluster │ online │ 2   │ 0%     │ 30.3 MB   │
│ www  │ 3  │ 0.0.1 │ cluster │ online │ 2   │ 0%     │ 29.5 MB   │
└──────┴────┴───────┴─────────┴────────┴─────┴────────┴───────────┘

Server

┌──────────┬────┬─────────┬───────┬────────┬─────────┬────────┬─────┬───────────┬──────┬──────────┐
│ App name │ id │ mode    │ pid   │ status │ restart │ uptime │ cpu │ mem       │ user │ watching │
├──────────┼────┼─────────┼───────┼────────┼─────────┼────────┼─────┼───────────┼──────┼──────────┤
│ www      │ 0  │ cluster │ 17523 │ online │ 0       │ 0s     │ 0%  │ 34.3 MB   │ root │ disabled │
│ www      │ 1  │ cluster │ 17529 │ online │ 0       │ 0s     │ 0%  │ 27.1 MB   │ root │ disabled │
│ www      │ 2  │ cluster │ 17543 │ online │ 0       │ 0s     │ 0%  │ 24.3 MB   │ root │ disabled │
│ www      │ 3  │ cluster │ 17567 │ online │ 0       │ 0s     │ 0%  │ 18.0 MB   │ root │ disabled │
└──────────┴────┴─────────┴───────┴────────┴─────────┴────────┴─────┴───────────┴──────┴──────────┘

As the result above my computer have 4 cores.

To make sure it work use pm2 logs you will see this.

1|www  | GET / 304 25ms
1|www  | GET /stylesheets/style.css 304 1ms
2|www  | GET / 304 112ms
2|www  | GET /stylesheets/style.css 304 1ms
2|www  | GET / 304 21ms
2|www  | GET /stylesheets/style.css 304 1ms

As you can see the number 1,2 are the app id. This mean that your app is running multiple core. each core for each id.

2. Use cluster module (native nodejs module) will need to change the code not recommended.

Code from nodejs document

const cluster = require('cluster');
const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
  console.log(`Master ${process.pid} is running`);

  // Fork workers.
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  cluster.on('exit', (worker, code, signal) => {
    console.log(`worker ${worker.process.pid} died`);
  });
} else {
  // Workers can share any TCP connection
  // In this case it is an HTTP server
  http.createServer((req, res) => {
    res.writeHead(200);
    res.end('hello world\n');
  }).listen(8000);

  console.log(`Worker ${process.pid} started`);
}

result

Master 8748 is running
Worker 8762 started
Worker 8761 started
Worker 8755 started
Worker 8768 started

https://www.youtube.com/watch?v=6xIbVPyh9wo

Test traffic handle improve

ab -c 40 -n 1000 http://localhost:3000/

no sluster.

Concurrency Level:      40
Time taken for tests:   7.407 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      349000 bytes
HTML transferred:       170000 bytes
Requests per second:    135.01 [#/sec] (mean)
Time per request:       296.269 [ms] (mean)
Time per request:       7.407 [ms] (mean, across all concurrent requests)
Transfer rate:          46.01 [Kbytes/sec] received

with sluster.

Concurrency Level:      40
Time taken for tests:   3.210 seconds
Complete requests:      1000
Failed requests:        0
Total transferred:      349000 bytes
HTML transferred:       170000 bytes
Requests per second:    311.51 [#/sec] (mean)
Time per request:       128.407 [ms] (mean)
Time per request:       3.210 [ms] (mean, across all concurrent requests)
Transfer rate:          106.17 [Kbytes/sec] received

Wow time taken for test: drop form 7s to 3s imazing.

Reference: https://nodejs.org/dist/latest-v10.x/docs/api/cluster.html