Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to deploy Node.js in cloud for high availability using multi-core, reverse-proxy, and SSL

I have posted this to ServerFault, but the Node.js community seems tiny there, so I'm hoping this bring more exposure.

I have a Node.js (0.4.9) application and am researching how to best deploy and maintain it. I want to run it in the cloud (EC2 or RackSpace) with high availability. The app should run on HTTPS. I'll worry about East/West/EU full-failover later.

I have done a lot of reading about keep-alive (Upstart, Forever), multi-core utilities (Fugue, multi-node, Cluster), and proxy/load balancers (node-http-proxy, nginx, Varnish, and Pound). However, I am unsure how to combine the various utilities available to me.

I have this setup in mind and need to iron out some questions and get feedback.

  1. Cluster is the most actively developed and seemingly popular multi-core utility for Node.js, so use that to run 1 node "cluster" per app server on non-privileged port (say 3000). Q1: Should Forever be used to keep the cluster alive or is that just redundant?
  2. Use 1 nginx per app server running on port 80, simply reverse proxying to node on port 3000. Q2: Would node-http-proxy be more suitable for this task even though it doesn't gzip or server static files quickly?
  3. Have minimum 2x servers as described above, with an independent server acting as a load balancer across these boxes. Use Pound listening 443 to terminate HTTPS and pass HTTP to Varnish which would round robin load balance across the IPs of servers above. Q3: Should nginx be used to do both instead? Q4: Should AWS or RackSpace load balancer be considered instead (the latter doesn't terminate HTTPS)

General Questions:

  1. Do you see a need for (2) above at all?
  2. Where is the best place to terminate HTTPS?
  3. If WebSockets are needed in the future, what nginx substitutions would you make?

I'd really like to hear how people are setting up current production environments and which combination of tools they prefer. Much appreciated.

like image 756
Chris F Avatar asked Aug 31 '11 15:08

Chris F


People also ask

Why should I use a reverse proxy if node js is production ready?

Also, scaling processes across different machines is something that cluster can't do. For these reasons it's sometimes better to use a reverse proxy to dispatch requests to running Node. js processes. Such reverse proxies can be dynamically configured to point to new application processes as they arrive.


2 Answers

It's been several months since I asked this question and not a lot of answer flow. Both Samyak Bhuta and nponeccop had good suggestions, but I wanted to discuss the answers I've found to my questions.

Here is what I've settled on at this point for a production system, but further improvements are always being made. I hope it helps anyone in a similar scenario.

  1. Use Cluster to spawn as many child processes as you desire to handle incoming requests on multi-core virtual or physical machines. This binds to a single port and makes maintenance easier. My rule of thumb is n - 1 Cluster workers. You don't need Forever on this, as Cluster respawns worker processes that die. To have resiliency even at the Cluster parent level, ensure that you use an Upstart script (or equivalent) to daemonize the Node.js application, and use Monit (or equivalent) to watch the PID of the Cluster parent and respawn it if it dies. You can try using the respawn feature of Upstart, but I prefer having Monit watching things, so rather than split responsibilities, I find it's best to let Monit handle the respawn as well.

  2. Use 1 nginx per app server running on port 80, simply reverse proxying to your Cluster on whatever port you bound to in (1). node-http-proxy can be used, but nginx is more mature, more featureful, and faster at serving static files. Run nginx lean (don't log, don't gzip tiny files) to minimize it's overhead.

  3. Have minimum 2x servers as described above in a minimum of 2 availability zones, and if in AWS, use an ELB that terminates HTTPS/SSL on port 443 and communicates on HTTP port 80 to the node.js app servers. ELBs are simple and, if you desire, make it somewhat easier to auto-scale. You could run multiple nginx either sharing an IP or round-robin balanced themselves by your DNS provider, but I found this overkill for now. At that point, you'd remove the nginx instance on each app server.

I have not needed WebSockets so nginx continues to be suitable and I'll revisit this issue when WebSockets come into the picture.

Feedback is welcome.

like image 103
Chris F Avatar answered Sep 20 '22 13:09

Chris F


You should not bother serving static files quickly. If your load is small - node static file servers will do. If your load is big - it's better to use a CDN (Akamai, Limelight, CoralCDN).

Instead of forever you can use monit.

Instead of nginx you can use HAProxy. It is known to work well with websockets. Consider also proxying flash sockets as they are a good workaround until websocket support is ubiquitous (see socket.io).

HAProxy has some support for HTTPS load balancing, but not termination. You can try to use stunnel for HTTPS termination, but I think it's too slow.

Round-robin load (or other statistical) balancing works pretty well in practice, so there's no need to know about other servers' load in most cases.

Consider also using ZeroMQ or RabbitMQ for communications between nodes.

like image 20
nponeccop Avatar answered Sep 23 '22 13:09

nponeccop