Skip to main content

Implementing load balancing with HAProxy in Node.js apps

What is a load balancer?

Load balancers distribute incoming client requests to computing resources such as application servers and databases. In each case, the load balancer returns the response from the computing resource to the appropriate client.

Why use a load balancer?

  • Preventing requests from going to unhealthy servers
  • Preventing overloading resources
  • Helping to eliminate a single point of failure

This introduction is enough to get started.

For this tutorial, we are going to use HAProxy which is a free, very fast, and reliable solution offering high availabilityload balancing, and proxying for TCP and HTTP-based applications.

We are not going to create a Node.js application here. For this tutorial let’s say you have a node.js application up and running on localhost:3000

When clients hits the server on localhost:3000 the server returns the appropriate response. Now let's say if we start sending a lot of requests to this single server, the server will get overloaded and the response time will decrease. Also if this server crashes client won’t be able to get the response. That means currently our app is not scalable and is not highly available.

There are two ways to address the scalability issue, we can allocate more resources such as ram to handle more user in less response time. That's called Vertical Scaling. The second approach would be to create multiple instances of your server and distribute the requests between them. This is known as Horizontal Scaling.

Now you may be wondering how effectively distribute the requests between those servers. This is where you can use HAProxy.

Image for post
HAProxy

Now let's set up the HAProxy.

  1. Install HAProxy in ubuntu
sudo apt-get update
sudo apt-get install haproxy

2. Configure the HAProxy

sudo nano /etc/haproxy/haproxy.cfg

3. Put this configuration in the haproxy.cfg

defaults
log global
mode http
option httplog
option dontlognull
timeout connect 5000
timeout client 50000
timeout server 50000
errorfile 400 /etc/haproxy/errors/400.http
errorfile 403 /etc/haproxy/errors/403.http
errorfile 408 /etc/haproxy/errors/408.http
errorfile 500 /etc/haproxy/errors/500.http
errorfile 502 /etc/haproxy/errors/502.http
errorfile 503 /etc/haproxy/errors/503.http
errorfile 504 /etc/haproxy/errors/504.http
frontend localnodes
bind *:80
mode http
default_backend nodes
backend nodes
mode http
balance roundrobin
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server app01 127.0.0.1:3000 check
server app02 127.0.0.1:3001 check
server app03 127.0.0.1:3002 check
listen stats
bind :9000
stats enable
stats uri /
stats hide-version
stats auth someuser:password

4. Restart the HAProxy

sudo service haproxy restart

Now go to localhost:9000 and you should be able to view the HAProxy statistics dashboard after providing username and password.

Image for post
HAProxy statistics dashboard

As you can see app01, app02 and app03 are showing as down.

Now go ahead and start your node server on localhost:3000, and two more servers on localhost:3001 and localhost:3002.

As soon as you start the server you can see the status on the HAProxy statistics dashboard.

Image for post

Now let’s send some requests to our load balancer, we don’t need to call localhost:3000 or localhost:3001 we can just hit on localhost since HAProxy running on port 80.

The load balancer should be able to get the requests and forward it to node.js servers using the Round Robin algorithm.

Create a script and make 10000 requests to your server. And you will be able to see that the requests have been balanced between these three servers.

This ensures that you will be able to handle the requests even if one of your servers goes down.

Image for post

As you can see above the 10,000 requests have been distributed effectively between the three servers.

You can choose your own algorithm for load balancing, lets try the Weighted Round Robin algorithm.

Update your haproxy.cfg with:

backend nodes
mode http
balance roundrobin
option forwardfor
http-request set-header X-Forwarded-Port %[dst_port]
http-request add-header X-Forwarded-Proto https if { ssl_fc }
option httpchk HEAD / HTTP/1.1\r\nHost:localhost
server app01 127.0.0.1:4321 weight 5 check
server app02 127.0.0.1:4322 weight 3 check
server app03 127.0.0.1:4323 weight 2 check

Here we have given the weight to each server. The app01 server has a weight of 5, app02 has 3 and app03 has 2.

Now let's see this in action, fire 10,000 requests, and see the statistics.

Image for post

Now as you can see the requests have been distributed as per the weight to three servers.

app01: 5000

app02: 3000

app03: 2000

You can use different load balancing algorithms as per your need.

If you are interested in System Design, also read how to setup Nginx as a reverse proxy here.

https://blog.shashi.dev/2021/01/setting-up-nginx-as-reverse-proxy-for.html

Thanks for reading. If you have some feedback, please provide your response or reach out to me on Twitter or Github.

Happy Coding!!!

Comments

Popular posts from this blog

Track stock market information right in your Terminal.

     Introduction: As a developer, I love working with the terminal. The plain, simple, and in my opinion the best way to interact with the computer (also it makes you look geeky). I spent most of my time in the terminal. By now you must have guessed I am a huge fan of the terminal and terminal-based applications. Recently I developed an interest in stock markets and started tracking the stock markets. Since I love working with the terminal I decided to build a terminal oriented application that can help me to track the stock market. Inspir e d by  wttr.in  I build  terminal-stocks  which can provide the stock's current prices, historical prices, and global market summary. How to use terminal-stocks terminal-stocks  is available and can be used without installation. Get the current price of the stock. curl terminal-stocks.dev/ITC.NS Current price of stocks You need to provide the ticker of the stock and terminal-stocks will give you the price inf...

PrivateGPT: A Step-by-Step Guide to Installation and Use

In this blog post, we will explore the ins and outs of PrivateGPT, from installation steps to its versatile use cases and best practices for unleashing its full potential. What is PrivateGPT? PrivateGPT is a cutting-edge program that utilizes a pre-trained GPT (Generative Pre-trained Transformer) model to generate high-quality and customizable text. Built on OpenAI's GPT architecture, PrivateGPT introduces additional privacy measures by enabling you to use your own hardware and data. This ensures that your content creation process remains secure and private. Installation Steps Before we dive into the powerful features of PrivateGPT, let's go through the quick installation process. PrivateGPT is a command line tool that requires familiarity with terminal commands. Let's get started: 1. Clone the Repository: Begin by cloning the PrivateGPT repository from GitHub using the following command: ``` git clone https://github.com/imartinez/privateGPT.git ``` 2.Navigate to the Direc...

Terraform accessing data from maps and list in the variable

In this post, we will discuss a use case where we want to access the variable value which is part of the list or the map. let’s try to understand the use case with an example: resource "aws_instance" "myec2" { ami = "ami-082b5a644766e0e6f" instance_type = <INSTANCE_TYPE> } variable "list" { type = list default = ["t2.nano", "t2.micro", "t2.medium"] } variable "types" { type = map default = { dev = "t2.nano", int = "t2.micro", prod = "t2.medium" }, } here we want to assign a value for the instance_type from either variable list or from variable types. Variable list is a list type and variable type is a map type. First, let’s use the list variable. To access the value from the list variable we will use the position. We want to assign let’s say t2.micro in that case we want position 1. resource "aws_instance...