Running multiple instances of nodejs server for scaling - node.js

I am running a nodejs server on port 8080, so my server can only process one request at a time.
I can see that if i send multiple requests in one single shot, new requests are queued and executed sequentially one after another.
What I am trying to find is, how do i run multiple instances/threads of this process. Example like gunicorn for python servers. Is there something similar, instead of running the nodejs server on multiple ports for each instance.
I have placed nginx infront of the node process. Is that sufficient and recommended method.
worker_processes auto;
worker_rlimit_nofile 1100;
events {
worker_connections 1024;
multi_accept on;
use epoll;
}
pid /var/run/nginx.pid;
http {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
server {
listen 80;
server_name localhost;
access_log /dev/null;
error_log /dev/null;
location / {
proxy_pass http://localhost:8080;
}
}
}

First off, make sure your node.js process is ONLY using asynchronous I/O. If it's not compute intensive and using asynchronous I/O, it should be able to have many different requests "in-flight" at the same time. The design of node.js is particularly good at this if your code is designed properly. If you show us the crux of what it is doing on one of these requests, we can advise more specifically on whether your server code is designed properly for best throughput.
Second, instrument and measure, measure, measure. Understand where your bottlenecks are in your existing node.js server and what is causing the delay or sequencing you see. Sometimes there are ways to dramatically fix/improve your bottlenecks before you start adding lots more clusters or servers.
Third, use the node.js cluster module. This will create one master node.js process that automatically balances between several child processes. You generally want to creates a cluster child for each actual CPU you have in your server computer since that will get you the most use out of your CPU.
Fourth, if you need to scale to the point of multiple actual server computers, then you would use either a load balancer or reverse proxy such as nginx to share the load among multiple hosts. If you had a quad core CPUs in your server, you could run a cluster with four node.js processes on it on each server computer and then use nginx to balance among the several server boxes you had.
Note that adding multiple hosts that are load balanced by nginx is the last option here, not the first option.

Like #poke said, you would use a reverse proxy and/or a load balancer in front.
But if you want a software to run multiple instances of node, with balancing and other stuffs, you should check pm2
http://pm2.keymetrics.io/

Just a point to be added here over #sheplu, the pm2 module uses the node cluster module under the hood. But even then, pm2 is a very good choice, as it provides various other abstractions other than node cluster.
More info on it here: https://pm2.keymetrics.io/docs/usage/pm2-doc-single-page/

Related

How does nginx load balances node instances

I have 3 cpu cores on my machine, and I have 3 instances of node running, one for each core. When I access such server directly, that's a master process that always gets called. However, when I use a reversed nginx proxy, the process is random. Where does nginx chooses which node process to run?
http://domain.com:1000 -> proxy
http://domain.com:2000 -> node processes
Nginx config:
server {
listen 1000;
server_name node;
location / {
proxy_pass http://domain.com:2000/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Nginx has no knowledge of your back-end's clustering the way you've configured it. As noted in a comment against your original question, Nginx load balancing only applies if you configure it with multiple backends. You are not doing this.
Therefore, if your backend itself is something like NodeJS using the Cluster module, the load balancing is happening there. Node doesn't need any "help" from Nginx to do this - it has its own mechanisms. They're described in https://nodejs.org/api/cluster.html#cluster_how_it_works:
The cluster module supports two methods of distributing incoming connections.
The first one (and the default one on all platforms except Windows), is the round-robin approach, where the master process listens on a port, accepts new connections and distributes them across the workers in a round-robin fashion, with some built-in smarts to avoid overloading a worker process.
The second approach is where the master process creates the listen socket and sends it to interested workers. The workers then accept incoming connections directly.
You can therefore choose how you want this to work in your Node back-end. At the moment, you are telling Nginx to always go to port 2000, therefore whatever you have running there is getting the traffic. If that is the master process for a Node Cluster, it will round-robin load balance. If that is one of the child workers, then that child worker will get ALL the traffic and the others will get none.

NGINX Reverse Proxy Causes 502 Errors On Some Pages

I have a Node.js/Express application running on an Ubuntu server. It sits behind an NGINX reverse proxy that passes traffic on port 80 (or 443 for ssl) to the application's port.
I've recently had an issue where for no identifiable reason, traffic trying to access / will eventually get a 504 error and timeout. As a test, I increased the timeout and am now getting a 502 error. I can access some other routes on my application, /login for example, with no problems.
When I restart my Express application, my app runs fine with no issues, usually for a few days until this happens again. Viewing the logs for my Express app, a good request looks something like:
GET / 200 15.786 ms - 1214
Whereas requests that aren't responding properly look like this:
GET / - - ms - -
This application has been running properly for about 13 months with no issues, this issue has arisen with no prompting. I haven't pushed any updates within the time that this has occurred.
Here is my NGINX config (modified a bit for security, e.g. example.com)
upstream site_upstream {
server 127.0.0.1:3000;
}
server {
listen 80;
listen 443 ssl;
server_name example.com;
ssl_certificate /etc/nginx/ssl/nginx.crt;
ssl_certificate_key /etc/nginx/ssl/nginx.key;
location / {
proxy_pass http://site_upstream;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
proxy_redirect http://rpa_upstream https://example.com;
}
}
I am unsure of if this an issue with my NGINX config or with my application itself as neither of my configurations have changed.
It sounds like a memory leak in either nginx or your Node application. If it starts to work again after restarting your Node application but without restarting nginx then it seems it's a problem with your Node app.
Try also accessing your app directly without a proxy to see what problems do you have in that case. You can sometimes get more detailed info that way in your browser's developer tools or with command-line tools like curl or benchmarks like Apache ab. Running heavy benchmarks with ab can help you spot the problems more quickly instead of waiting.
Of course it's hard to say what's exactly the problem when you don't show any code.
If it was working fine before, and if you didn't upgrade anything (your app, any Node modules, or Node itself) during that time, then maybe your traffic increased slightly and now you start seeing the problems that were not manifesting before. Or maybe your system now uses more RAM for other tasks and the memory leak starts to be a problem quicker than before.
You can start logging data returned by process.memoryUsage() on a regular intervals and see if anything looks problematic.
Also monitor your Node processes with ps, top, htop or other commands, or see the memory usage /proc/PID/status etc.
You can also monitor /proc/meminfo on regular intervals and see if the total memory used in your system is correlated with your application getting unresponsive.
Another thing that may be causing problems is for example conenctions to your database responding slowly or not at all, if you are not handling errors and timeouts inside of your application. Adding more extensive logging (a line entering every route handler, a line before every I/O opertation starts and after every I/O operation either succeeds or fails or times out) should give you some more insight into it.

Multiple nodejs workers in docker

I'm very new to docker and productionizing nodejs web apps. However, after some reading I've determined that a good setup would be:
nginx container serving static files, ssl, proxying nodejs requests
nodejs container
postgesql container
However, I'm now trying to tackle scalability. Seeing as you can define multiple proxy_pass statements in an nginx config, could you not spin up a duplicate nodejs container (exactly the same but exposing a different port) and effectively "load balance" your web app? Is it a good architecture?
Also, how would this effect database writes? Are there race conditions I need to specifically architecture for? Any guidance would be appreciated.
Yes, it's possible to use Nginx to load balance requests between different instances of your Node.js services. Each Node.js instance could be running in a different Docker container. Increasing the scalability of your configuration is as easy as starting up another Docker container and ensure it's registered in the Nginx config. (Depending on how often you have to update the Nginx config, a variety of tools/frameworks are available to do this last step automatically.)
For example, below is an Nginx configuration to load balance incoming requests across different Node.js services. In our case, we have multiple Node.js services running on the same machine, but it's perfectly possible to use Docker containers instead.
File /etc/nginx/sites-enabled/apps:
upstream apps-cluster {
least_conn;
server localhost:8081;
server localhost:8082;
server localhost:8083;
keepalive 512;
}
server {
listen 8080;
location "/" {
proxy_next_upstream error timeout http_500 http_502 http_503 http_504;
proxy_set_header Connection "";
proxy_http_version 1.1;
proxy_pass http://apps-cluster;
}
access_log off;
}
Despite running multiple instances of your Node.js services, your database should not be negatively affected. The PostgreSQL database itself can perfectly handle multiple open connections and automatically resolves any race conditions. From a developer point of view, the code for running 1 Node.js service is the same as for running x Node.js services.
You can set "Function Level Concurrent Execution Limit" on the function you are using to connect to RDS. This will contain the number of RDS connections. The requests from Dynamo will be throttled though.
Another option is to stream them into Kinesis or SQS from this lambda and have another worker lambda to read it from there and pump the data into RDS. This is scalable and reliable with no throttling.

Is it possible to switch database to test database on node.js?

I want to run e2e tests like protractor (or other Selenium tests) on developement server. Is it possible to switch to different - test database for the testing time? I am loading fixtures before each test runs.
What are good practices for this kind of testing - with node.js and mongo.db in backend, concerning database setup?
Thank you in advance.
The easiest way to do it IMHO would be to spin up another instance of your application with different configuration, namely connecting to a different database and listening on a different port. Then you can point Selenium to it. In theory the FE of the application should be port agnostic, however if that presents a problem, nginx can be of a great help.
Let's consider you want it on port 3333 and domain test.myapp. Here is sample configuration file for nginx.
server {
listen 80;
server_name test.myapp;
location / {
proxy_pass http://localhost:3333;
proxy_set_header Host $host;
proxy_buffering off;
}
}
Of course you would like to have another server defined for your current development server. Simply rinse and repeat.
Usually the configuration in a nodejs application is chosen based on the value of environmental variable NODE_ENV. You can pass it like so, when you run your app (I am assuming here it is a Linux server):
$ NODE_ENV=test node app.js
Then inside your application you would easily get access to it:
var env = process.env.NODE_ENV
I hope it helps.
Mocha can now accept a --config file which could be used to point to a different database. I use the same database server, a server can have multiple databases, this makes it very simple and lightweight for a developer.
https://www.w3resource.com/mocha/command-line-usage.php

How to make Node.js Multi-tenant for websites on port 80?

My end goal is to make node.js more cost effective per each server instance.
I'm not running a game or chat room but rather simple websites for customers. I would like to house multiple clients on a single server yet have multiple websites running off of port 80 using host header mapping. I would like to still use express as I'm doing but have it be more like a routing thing from port 80 to the other node apps if that is even possible. Node can be cheaper if its done in this way but currently its more expensive for my purposes as each customer would need their own box if running on port 80. Also, my motivation is to focus on node development but there must be a reason to do so in terms of cost.
I do this quite a lot for ASP.NET in Windows as IIS supports this out of the box and I know this is something normal for Apache as well.
Feel free to move this to another forum in stack exchange if this is not the right question or give constructive criticism rather than a random downvote. Thanks.
update
The approach I took was to use static hosting (via gatspy and s3) then an API instead that registered domains through post message from the client and API keys from the server and generates static sites periodically as sites change but thanks for all the suggestions!
In theory, you could build a pure-Node web server that emulated the functionality of Apache/Lighttpd/Nginx, but I wouldn't recommend it. In fact, for serious production services, I'd recommend ALWAYS fronting your service with Nginx or an equivalent (see this and this).
Here's how a simple Nginx config would work for two subservices exposed on port 80.
worker_processes 4;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type text/html;
server {
listen 80;
server_name service1.mydomain.com
location / {
proxy_pass http://127.0.0.1:3000/;
}
}
server {
listen 80;
server_name service2.mydomain.com
location / {
proxy_pass http://127.0.0.1:3001/;
}
}
}
I've seen production boxes kernel panic because Node doesn't throttle load by default and was prioritizing accepting new connections over handling existing requests - granted, it "shouldn't" have crashed the kernel, but it did. Also, by running on port 3000, you can run your Node service as non-root with very few permissions (and still proxy it so that it appears to be on port 80). You can also spread load between multiple workers, serve statics, log requests, rewrite urls, etc, etc, etc. Nginx is very fast (much lighter than Apache). The overhead of same-box proxy forwarding is minimal and buys you so much functionality and robustness that it's a slam dunk in my book. Even minor stuff, like - when I crash or overload my node service, do user get a black hole, or a "pardon our dust, our servers are being maintained" splash.
What about using a proper reverse proxy, like HAProxy, have the proxy listen on port 80, and delegate to multiple node instances on non public ports (e.g. 10000, 10001 etc.), based on headers.host?

Resources