Simple NodeJs server managed by PM2 for performance optimizations and reversed proxy via nginx. The setup is run in Docker containers. Docker makes it easy to pass env variables to nginx
Node Js is single threaded and even if we run it on a server with multiple cores, it will still use a single thread(process).
Node has a cluster module that allows us to take advantage of multi core systems.
It helps to create child process which share same server port but runs on different processes on the CPU core.
Processes are basically scoped containers running our code.
Node comprises of the following:
// update the default thread pool from 4 to 2 process.env.UV_THREADPOOL_SIZE = 2;
This is the basic flow how the code we write flows in the Node land:
JS code ---> JS Engine(V8) ---> NodeJS APIs ---> Node bindings ---> Libuv
Basic non blocking operatiosn are:
Basic blocking operations are:
We can use the Node cluster module to spin up child process and make our code use the multi core cpu, but the management of these child process can get cumbersome, that's why in production its prefered to use PM2. The definition of PM2 from its website
PM2 is a daemon process manager that will help you manage and keep your application online 24/7
We can configure PM2 either using cli arguments or the config file, and in this repo we have used the config file ecosystem.config to configure our PM2. Here is our basic configuration:
4 \* 2 = 8.module.exports = { apps: [ { name: "node-be", script: "./server-pm2.js", exec_mode: "cluster", instances: "max", log_type: "json", log_file: "./logs/log.json", out_file: "./logs/out.json", error_file: "./logs/error.json", env: { PORT: 3000, SERVER_NO: "Server 1", }, }, { name: "node-be-2", script: "./server-pm2.js", .... env: { PORT: 3001, SERVER_NO: "Server 2", }, }, ], };
cli here is an example:
pm2 start server.js -i 0
Nginx is a web server that can also be used as a reverse proxy, load balancer, mail proxy and HTTP cache. We have used it for reverse proxy and load balancing.
template setup of NGINX bcs it works well with environment variables and let us substitute the values when the docker image for NGINX runs.default.conf.template file that holds the server directive that will be overriding the default one.// default.conf.template file server { listen ${NGINX_PORT}; server_name ${NGINX_HOST}; location / { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header Host $host; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; proxy_pass http://${SERVER_HOST}:${SERVER_PORT}/; proxy_http_version 1.1; } }
upstream to work with nginx and docker locally we have to switch from using
localhost in upstream to the local ip instead 172.18.0.1// instead of upstream nodeapi { server localhost:${SERVER_PORT}; server localhost:${SERVER_PORT2}; } // to using local ip upstream nodeapi { server 172.18.0.1:${SERVER_PORT}; server 172.18.0.1:${SERVER_PORT2}; }
For local development make sure the following things are setup:
npm install for installing the dependencies..env file provided feel free to update the values. But make sure the PORT values match the PM2 config.docker composr up --build ---> to re build the image docker compose up --> if image exists docker exec -it nginx-server sh ---> to checks thr logs in docker container. Here `nginx-server` is the name of the container.