Node.js on multi-core machines
Asked Answered
T

17

708

Node.js looks interesting, BUT I must miss something - isn't Node.js tuned only to run on a single process and thread?

Then how does it scale for multi-core CPUs and multi-CPU servers? After all, it is all great to make fast as possible single-thread server, but for high loads I would want to use several CPUs. And the same goes for making applications faster - seems today the way is use multiple CPUs and parallelize the tasks.

How does Node.js fit into this picture? Is its idea to somehow distribute multiple instances or what?

Takahashi answered 5/3, 2010 at 15:13 Comment(3)
It looks like Ryah is starting to get serious about including built-in multi-core support in node: github.com/joyent/node/commit/…Lifelike
PM2 process manager use cluster module internally to spread your NodeJS apps to all cores available : github.com/Unitech/pm2Purree
@broofa, Those are not real threads and child processes have no shared memory. Also see What's the Nodejs equivalent of Java's real threading and volatile-static variables?.Harlotry
M
775

[This post is up-to-date as of 2012-09-02 (newer than above).]

Node.js absolutely does scale on multi-core machines.

Yes, Node.js is one-thread-per-process. This is a very deliberate design decision and eliminates the need to deal with locking semantics. If you don't agree with this, you probably don't yet realize just how insanely hard it is to debug multi-threaded code. For a deeper explanation of the Node.js process model and why it works this way (and why it will NEVER support multiple threads), read my other post.

So how do I take advantage of my 16 core box?

Two ways:

  • For big heavy compute tasks like image encoding, Node.js can fire up child processes or send messages to additional worker processes. In this design, you'd have one thread managing the flow of events and N processes doing heavy compute tasks and chewing up the other 15 CPUs.
  • For scaling throughput on a webservice, you should run multiple Node.js servers on one box, one per core and split request traffic between them. This provides excellent CPU-affinity and will scale throughput nearly linearly with core count.

Scaling throughput on a webservice

Since v6.0.X Node.js has included the cluster module straight out of the box, which makes it easy to set up multiple node workers that can listen on a single port. Note that this is NOT the same as the older learnboost "cluster" module available through npm.

if (cluster.isMaster) {
  // Fork workers.
  for (var i = 0; i < numCPUs; i++) {
    cluster.fork();
  }
} else {
  http.Server(function(req, res) { ... }).listen(8000);
}

Workers will compete to accept new connections, and the least loaded process is most likely to win. It works pretty well and can scale up throughput quite well on a multi-core box.

If you have enough load to care about multiple cores, then you are going to want to do a few more things too:

  1. Run your Node.js service behind a web-proxy like Nginx or Apache - something that can do connection throttling (unless you want overload conditions to bring the box down completely), rewrite URLs, serve static content, and proxy other sub-services.

  2. Periodically recycle your worker processes. For a long-running process, even a small memory leak will eventually add up.

  3. Setup log collection / monitoring


PS: There's a discussion between Aaron and Christopher in the comments of another post (as of this writing, its the top post). A few comments on that:

  • A shared socket model is very convenient for allowing multiple processes to listen on a single port and compete to accept new connections. Conceptually, you could think of preforked Apache doing this with the significant caveat that each process will only accept a single connection and then die. The efficiency loss for Apache is in the overhead of forking new processes and has nothing to do with the socket operations.
  • For Node.js, having N workers compete on a single socket is an extremely reasonable solution. The alternative is to set up an on-box front-end like Nginx and have that proxy traffic to the individual workers, alternating between workers for assigning new connections. The two solutions have very similar performance characteristics. And since, as I mentioned above, you will likely want to have Nginx (or an alternative) fronting your node service anyways, the choice here is really between:

Shared Ports: nginx (port 80) --> Node_workers x N (sharing port 3000 w/ Cluster)

vs

Individual Ports: nginx (port 80) --> {Node_worker (port 3000), Node_worker (port 3001), Node_worker (port 3002), Node_worker (port 3003) ...}

There are arguably some benefits to the individual ports setup (potential to have less coupling between processes, have more sophisticated load-balancing decisions, etc.), but it is definitely more work to set up and the built-in cluster module is a low-complexity alternative that works for most people.

Mosera answered 31/12, 2011 at 2:48 Comment(21)
can you offer any advice for running different nodejs based services on one box? E.g. Say I have 1 server, and want to run myservice1.js on CpuCore1, and myservice2.js on CpuCore2. Can I use cluster for this? or is it only useful for creating cloned services?Muir
You should post a question for that! (and I'll copy this comment over as your 1st answer). What you are wanting to do is actually really really simple. You wouldn't really need "cluster", you'd just run two different node services. Two scripts, two processes, two ports. Eg, you could have serviceA listen on 3000 and serviceB listen on 3001. Each of those services might use "cluster" to have 1+ workers and recycle them periodically, etc. Then you could configure Nginx to listen on port 80 and to forward to the correct service based on the incoming "Host" header and / or the URL path.Mosera
Thanks. I've posted a related question already - you described pretty much what I had in mind, but I'm unsure about how to target CPU cores (when using something like forever).Muir
Great answer ddopson. What is the best way to have two node processes communicate with each other on the same machine? Is there a faster protocol than TCP when they're on the same machine?Cavity
@WindUpToy - first, you are probably overthinking it. TCP is really fast. 2nd, you should open a new question so I can write a longer answer. The meta-answer is to use whatever feels natural and leads to the cleanest code. You should look at Node's built-in IPC mechanism. Under the covers, it uses a UNIX pipe to communicate to the child, but wraps that in a higher-level semantic.Mosera
Why can't we still have a single thread, as in keep the event model and everything the same, but have the underlying system automatically divide out that thread to the cores so it can do all the stuff faster rather than at the same time, could we achieve speeds faster than 10000 people could hit at the 'same time'? If we measured time small enough we would probably find that they did not hit the server at the same time.Caloyer
@ioSamurai We have something you mentioned and that is called distributed computing, this is ore of OS level rather than something node.js could do.Pygmy
can I use amazon ELB instead of nginx? would ELB accomplish the same thing as nginx which is to load balance?Nobile
@Nobile - Technically, ELB and Nginx are complimentary. Under the hood, ELB is an EC2 instance running some LB software (heh, which might even USE Nginx for all we know!) that proxies requests to your service instances. You might still run Nginx on each server instance for various reasons (static content, etc). On the other hand, if you achieve everything you need with ELB, NOT running Nginx is less of a concern if end-users can't hit your Node.js endpoints directly.Mosera
Also, check out github.com/defunkt/unicorn/blob/master/DESIGN. Node.js, being evented, alleviates some of the concerns addressed in that doc, but it's still a really interesting and insightful write-up.Mosera
For the numbered list of "a few more things" to do for multi-core node, I'd love to see some links for further reading... Thanks!Disturb
I tested node recently and it can eat more than 100% (reported by top) of the CPU, so it can actually use all of the cores on a single cpu, but you need another process to use a second cpu. Right?Petiolate
@matejkramny - Each "core" is a separate CPU and it's irrelevant to most software which cores happen to be collocated on the same rectangular bit of silicon. The JS event loop only runs on a single core. As for why you see >100% CPU usage, there's two possibilities: 1) imprecise measurement, or 2) There is one slight caveat for the native layer that sits below the JS code ... hypothetically, a platform implementation of NodeJS could use extra worker threads to process IO.Mosera
I've got a question concerning splitting request traffic between multiple cores: #22457794Rosenkrantz
@DaveDopson How could i recycle workers process periodically? Sorry, I know its not a right place to ask this. but it will help me and others. Thank you.Capablanca
@HumanLove - After some (random!) quantity of time, a worker might close its listener, stop accepting new requests, and gracefully die, causing a new worker to get created. This is a workaround for the gradual accumulation of small memory leaks. It's a pretty common pattern on IIS / gunicorn / etc. eg #15397972Mosera
@DaveDopson Thanks Dave. I have found this article schier.co/blog/2013/01/06/…. Does this small trick will restart process periodically? It's a very small article and easy code. Let me know your opinions about it. Thanks.Capablanca
@DaveDopson Is there a way to scale Node.js app on a real cluster (not about library but the net of machines :) )Paramecium
@Paramecium - well, yes. Running a Node.js app on multiple machines is very common. There's no library needed to do so. You just run your code on multiple machines and distribute load between them. Architecting your software so that it scales (ie, it stores state in some sort of external data service rather than keeping state in memory) - that's your job.Mosera
Suppose if i am having multiple instance of node app running like one for Account's at port 2000 and Transactionat Port 3000. Will this use multithread ? Looking forward for a reply.Doan
You contadict yourself. You wrote that it is hard to "debug multi-threaded code" and then you say run multiple instances. Multiple instances under the hood means multiple threads.Chivalric
C
49

One method would be to run multiple instances of node.js on the server and then put a load balancer (preferably a non-blocking one like nginx) in front of them.

Clutter answered 10/3, 2010 at 5:47 Comment(11)
node.js is about as fast as nginx, you could put a node.js load balancer in front of your node.js servers if you wanted to as well :)Hara
ryan specifically said not to do this until node was more stable. Best way is to run nginx in front of node.Affirmatory
as for nginx in front of node, it won't solve certain problems like if you have an in-memory queue. 2 node instances will not be able to access each other's queue.Affirmatory
As well, nginx doesn't support HTTP 1.1 fully, so things like WebSockets can not be proxied.Slush
@Affirmatory this is by designCrescendo
You shouldn't do this, but if you are going to do it, I'd recommend using haproxy over nginx. For straightforward load balancing, it actually tends to be more efficient.Tiphane
@mikeal, resopollution - I'm strongly on the Nginx side. I hard-crashed Node.js multiple times (no stacktrace, just dies). I've never crashed Nginx. Nginx out-of-the-box is configured with all sorts of sane throttles. Node.js by default will continue accepting new connections in preference to serving existing ones until the box goes down... yes, the entire box; I crashed the kernel on a CentOS5 box by stress-testing Node (now THAT really isn't supposed to happen). I've come around a bit, and I see a bright future for Node, potentially including dedicated LB-type roles. Just not yet.Mosera
@Affirmatory - see above (max 1 at_mention per comment)Mosera
Is there a way to scale Node.js app on a real machine cluster?Paramecium
How can I ensure the multiple instances are distributed into different cores? Will the OS scheduler automatically distribute node instances into CPU cores or I have to manually specify CPU core for each instance?Epistemic
Yes, the OS will take care of that. If multiple processes are in runnable state, they will be scheduled on different cores.Clutter
L
34

Ryan Dahl answers this question in the tech talk he gave at Google last summer. To paraphrase, "just run multiple node processes and use something sensible to allow them to communicate. e.g. sendmsg()-style IPC or traditional RPC".

If you want to get your hands dirty right away, check out the spark2 Forever module. It makes spawning multiple node processes trivially easy. It handles setting up port sharing, so they can each accept connections to the same port, and also auto-respawning if you want to make sure a process is restarted if/when it dies.

UPDATE - 10/11/11: Consensus in the node community seems to be that Cluster is now the preferred module for managing multiple node instances per machine. Forever is also worth a look.

Lifelike answered 9/12, 2010 at 12:46 Comment(5)
Forever and Cluster do very different things. You might even use both. Forever restarts a process when it dies. Cluster manages multiple workers. You'd use Forever to manage your master process...Mosera
also, the learnboost module is largely supplanted by the version of Cluster baked into Node v0.6.x (warning: the API surface does differ)Mosera
@Lifelike How is the default IPC compared to lets say using Redis or Memcache wile just sending string/data/arrays in between processes? Which way would be faster?Intermediate
@broofa, IPC has huge overheads compared to real shared memory that Java and C are capable of doing.Harlotry
@Harlotry True, but shared memory only solves the problem of how to scale in the context of a single host, without addressing the macro issues needed to scale across many hosts. I.e. How to run in the Cloud.Lifelike
A
31

You can use cluster module. Check this.

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

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

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {
    // Workers can share any TCP connection
    // In this case its a HTTP server
    http.createServer(function(req, res) {
        res.writeHead(200);
        res.end("hello world\n");
    }).listen(8000);
}
Admissible answered 27/4, 2014 at 20:23 Comment(0)
G
19

Node Js is supporting clustering to take full advantages of your cpu. If you are not not running it with cluster, then probably you are wasting your hardware capabilities.

Clustering in Node.js allows you to create separate processes which can share same server port. For example, if we run one HTTP server on Port 3000, it is one Server running on Single thread on single core of processor.

Code shown below allow you to cluster your application. This code is official code represented by Node.js.

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

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

    Object.keys(cluster.workers).forEach(function(id) {
        console.log("I am running with ID : " + cluster.workers[id].process.pid);
    });

    cluster.on('exit', function(worker, code, signal) {
        console.log('worker ' + worker.process.pid + ' died');
    });
} else {

    //Do further processing.
}

check this article for the full tutorial

Gaberdine answered 2/10, 2015 at 14:53 Comment(0)
M
14

Multi-node harnesses all the cores that you may have.
Have a look at http://github.com/kriszyp/multi-node.

For simpler needs, you can start up multiple copies of node on different port numbers and put a load balancer in front of them.

Martensite answered 20/7, 2010 at 10:4 Comment(0)
M
14

As mentioned above, Cluster will scale and load-balance your app across all cores.

adding something like

cluster.on('exit', function () {
  cluster.fork();
});

Will restart any failing workers.

These days, a lot of people also prefer PM2, which handles the clustering for you and also provides some cool monitoring features.

Then, add Nginx or HAProxy in front of several machines running with clustering and you have multiple levels of failover and a much higher load capacity.

Marbling answered 5/2, 2015 at 15:52 Comment(1)
PM2 is great for production use. The monitoring tools have helped me work out memory problems with apps.Hypertonic
R
14

The cluster module allows you to utilise all cores of your machine. In fact you can take advantage of this in just 2 commands and without touching your code using a very popular process manager pm2.

npm i -g pm2
pm2 start app.js -i max
Ronnie answered 21/11, 2016 at 22:36 Comment(0)
H
9

Future version of node will allow you to fork a process and pass messages to it and Ryan has stated he wants to find some way to also share file handlers, so it won't be a straight forward Web Worker implementation.

At this time there is not an easy solution for this but it's still very early and node is one of the fastest moving open source projects I've ever seen so expect something awesome in the near future.

Hara answered 13/3, 2010 at 18:51 Comment(0)
U
8

You may run your node.js application on multiple cores by using the cluster module on combination with os module which may be used to detect how many CPUs you have.

For example let's imagine that you have a server module that runs simple http server on the backend and you want to run it for several CPUs:

// Dependencies.
const server = require('./lib/server'); // This is our custom server module.
const cluster = require('cluster');
const os = require('os');

 // If we're on the master thread start the forks.
if (cluster.isMaster) {
  // Fork the process.
  for (let i = 0; i < os.cpus().length; i++) {
    cluster.fork();
  }
} else {
  // If we're not on the master thread start the server.
  server.init();
}
Ultrasonic answered 20/9, 2018 at 12:41 Comment(0)
P
7

Spark2 is based on Spark which is now no longer maintained. Cluster is its successor, and it has some cool features, like spawning one worker process per CPU core and respawning dead workers.

Punctuate answered 8/3, 2011 at 13:2 Comment(1)
The original question and a lot of these answers are a few months old and with node moving so fast I appreciate you adding the blurb about Cluster. After looking at Cluster and its examples, it looks exactly like what I (or the OP?) want for Node, thanks!Newbold
B
6

I'm using Node worker to run processes in a simple way from my main process. Seems to be working great while we wait for the official way to come around.

Bra answered 24/5, 2010 at 17:23 Comment(1)
why node worker example.js can't run, my node is 0.3.3 pre versionGer
M
6

💢 IMPORTANT DIFFERENCE - ROLLING RESTART

I have to add an important difference between using node's build in cluster mode VS a process manager like PM2's cluster mode.

PM2 allows zero down time reloads when you are running.

pm2 start app.js -i 2 --wait-ready

In your codes add the following

process.send('ready');

When you call pm2 reload app after code updates, PM2 will reload the first instance of the app, wait for the 'ready' call, then it move on to reloads the next instance, ensuring you always have an app active to respond to requests.

While if you use nodejs' cluster, there will be down time when you restart and waiting for server to be ready since there is only one instance of the app and you are restarting all the cores together.

Melodie answered 29/1, 2021 at 9:9 Comment(0)
C
5

The new kid on the block here is LearnBoost's "Up".

It provides "Zero-downtime reloads" and additionally creates multiple workers (by default the number of CPUs, but it is configurable) to provide the best of all Worlds.

It is new, but seems to be pretty stable, and I'm using it happily in one of my current projects.

Collude answered 3/2, 2012 at 19:14 Comment(0)
O
2

I searched for Clusterize an app for all CPU cores available and found my myself here. Where I found this keyword Is Pm2 command

pm2 examples

This is what I found

  • Clusterize an app to all CPU cores available:

    $ pm2 start -i max

If you need to install pm2 use these commands

npm install -g pm2

yan add -g pm2

or

Use this link Here

Obstetrics answered 7/11, 2021 at 5:51 Comment(1)
One thing I like about this answer is that it's showing there are ways to separate the multi-core concern from your Node.js codebase, if you have the right architectural constraints in place (i.e. like being a stateless node.js app). Kubernetes deployments have this notion of replicas, which is another way to go multi-core and scale your node.js app. See this article: learnk8s.io/deploying-nodejs-kubernetes#defining-a-deploymentProperly
F
0

It's also possible to design the web-service as several stand alone servers that listen to unix sockets, so that you can push functions like data processing into seperate processes.

This is similar to most scrpting/database web server architectures where a cgi process handles business logic and then pushes and pulls the data via a unix socket to a database.

the difference being that the data processing is written as a node webserver listening on a port.

it's more complex but ultimately its where multi-core development has to go. a multiprocess architecture using multiple components for each web request.

Forkey answered 12/4, 2010 at 0:39 Comment(0)
C
0

It's possible to scale NodeJS out to multiple boxes using a pure TCP load balancer (HAProxy) in front of multiple boxes running one NodeJS process each.

If you then have some common knowledge to share between all instances you could use a central Redis store or similar which can then be accessed from all process instances (e.g. from all boxes)

Captive answered 10/11, 2011 at 15:14 Comment(1)
Unless you've got single core CPUs in those servers, that's not going to utilise all your CPU capacity (unless you're doing something else too).Muir

© 2022 - 2024 — McMap. All rights reserved.