Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

clustering in node.js is not working. Only one worker is always responding

I am practising clustering in node.js I am having a two core CPU. I created two workers and each worker runs a simple http server. Server response callback will block for 5 sec to give next request to other worker. To verify workers are working parallel, I have opened multiple tabs in Firefox and refreshed each. problem is always(99%) only one worker is responding requests that was make by refreshing tabs. Only one request is being served by one worker and all other requests are blocked until that worker is finished. My code is here CODE:

var cluster = require('cluster');
var http = require('http');



if (cluster.isMaster) {
    var cpus = require('os').cpus().length;
    console.log('No of cpus:' + cpus);
    console.log(require('os').cpus());

    for (var i = 0; i < cpus; i++) {
        cluster.fork();
    }

    cluster.on('fork', function(worker) {
        console.log('worker:' + worker.id + " is forked");
    });
    cluster.on('online', function(worker) {
        console.log('worker:' + worker.id + " is online");
    });
    cluster.on('listening', function(worker) {
        console.log('worker:' + worker.id + " is listening");
    });
    cluster.on('disconnect', function(worker) {
        console.log('worker:' + worker.id + " is disconnected");
    });
    cluster.on('exit', function(worker) {
        console.log('worker:' + worker.id + " is dead");
    });

} else {
    http.createServer(function(req, res) {

        console.log('worker:' + cluster.worker.id + " going to send response ");
        res.writeHead(200);
        res.end("hello world. worker: " + cluster.worker.id);
        var stop = new Date().getTime();
        while (new Date().getTime() < stop + 5000) {;
        }
    }).listen(8000);
}

OUTPUT:

20 Aug 00:36:11 - [nodemon] restarting due to changes...
20 Aug 00:36:12 - [nodemon] starting `node cluster.js`
No of cpus:2
[ { model: 'Intel(R) Core(TM)2 Duo CPU     E4500  @ 2.20GHz',
    speed: 2200,
    times: { user: 2264671, nice: 0, sys: 698343, idle: 5965109, irq: 98812 } },
  { model: 'Intel(R) Core(TM)2 Duo CPU     E4500  @ 2.20GHz',
    speed: 2200,
    times: { user: 2466000, nice: 0, sys: 502562, idle: 5959203, irq: 4609 } } ]
worker:1 is forked
worker:2 is forked
worker:2 is online
worker:1 is online
worker:2 is listening
worker:1 is listening
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response
worker:1 going to send response

I have noticed one thing. If I force reload(ctrl+f5) the tab, then both workers is responding one after other. OUTPUT:

worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response
worker:1 going to send response
worker:2 going to send response

I am confused what,s happening here for normal refresh(f5) and force reload( ctrl + f5 ). help me to figure it out...!

like image 623
cJ_ Avatar asked Aug 19 '14 19:08

cJ_


People also ask

How clustering works in Nodejs?

The cluster module enables creating child processes (workers) that run simultaneously while sharing the same server port. Every child process has its own event loop, memory, and V8 instance. The child processes use interprocess communication to communicate to the main parent Node. js process.

Is it possible to cluster multiple node processes?

js provides for scaling up the applications is to split a single process into multiple processes or workers, in Node. js terminology. This can be achieved through a cluster module. The cluster module allows you to create child processes (workers), which share all the server ports with the main Node process (master).

What is the difference between node js child process and clusters?

In a single thread, the individual instance of node. js runs specifically and to take advantage of various ecosystems, a cluster of node. js is launched, to distribute the load. With the help of a cluster module, child processes can be created very easily sharing the server ports.

Why is node js not suitable for CPU intensive work?

However, there is a downside to Node. js being single-threaded. The single-threaded implementation makes Node a bad choice for CPU-intensive programs. When a time-consuming task is running in the program it blocks the event loop from moving forward for a longer period.


2 Answers

TIL on the surface node clustering does not appear to do what it says it does (at least to me).

I was in the same situation you were, observing the same worker process always being given a request when I spawned them synchronously from a browser. A colleague of mine used fiddler to replay ~20 requests at once. When all of those requests hit the server very fast, faster than the cluster manager can pass them off to workers (I'm guessing), then you will see additional workers being invoked with requests.

It seems that once the manager hands off the request to a worker, it doesn't know/care about the worker blocking. It just knows that there is only one request in the pipe and there is no need to give that request to anyone other than the first worker because, as far as the manager knows, he's available.

like image 181
BoxerBucks Avatar answered Sep 30 '22 06:09

BoxerBucks


The while loop you have in your response code could be causing some serious problems. You should be using a setTimeout there if you want to simulate a long running request.

Try this for your worker instead:

http.createServer(function(req, res) {
    console.log('worker:' + cluster.worker.id + " going to send response ");
    setTimeout(function() {
       res.writeHead(200);
       res.end("hello world. worker: " + cluster.worker.id);
    }, 5000);
}).listen(8000);

That being said, what @dandavis said in the comments is true: cluster does not do round-robin load balancing so, as long as Worker 1 is available for requests, it will handle them. Using setTimeout like I suggested will actually make your workers more available to handle requests so it's likely that you'll only see Worker 1 handle requests if you're just hitting the server manually from a browser. You might need some sort of load testing script to see both workers handling requests.

As for the difference you're seeing between F5 and CTRL-F5, my best guess is that your browser is keeping the connection to the server alive so, when you just use F5, it uses the same connection which will always go to the same worker. When you use CTRL-F5 it's actually closing the connection that it had before and therefor could connect to either worker on the next request.

like image 43
Mike S Avatar answered Sep 30 '22 08:09

Mike S