Load balancing with Nginx
When an application becomes popular and the number of requests increases beyond the capacity of a single server, we need to scale horizontally. We can always increase the capacity (vertical scaling) of a server by adding more memory and processing power, but a single server cannot scale beyond a certain limit. While adding separate servers or replicas of the application server, we need a mechanism which directs the traffic between these replicas. The hardware or software tool used for this purpose is known as a load balancer. Load balancers work as transparent mechanisms between the application server and client by distributing the requests between available instances. This is a commonly used technique for optimizing resource utilization and ensuring fault tolerant applications.
Nginx can be configured to work as an efficient Layer 7 as well as Layer 4 load balancer. Layer 7 is application layer of HTTP traffic. With Layer 4 support, Nginx can be used to load balance database servers or even XMPP traffic. With version 1.9.0, Nginx has enabled support for Layer 4 load balancing in their open source offerings.
In this recipe, we will learn how to set up Nginx as a load balancer.
Getting ready
You will need access to a root account or an account with sudo
privileges.
You will need a minimum of three servers, as follows:
- An Nginx server, which will be set as a load balancer
- Two or more application servers with a similar code base set up on all
How to do it…
Follow these steps to set load balancing with Nginx:
- I assume that you already have Nginx installed. If not, you can refer to the Installing Nginx with PHP_FPM recipe of this chapter.
- Now, create a new configuration file under
/etc/nginx/sites-available
. Let's call itload_balancer
:$ sudo nano /etc/nginx/sites-available/load_balancer
- Add the following lines to this
load_balancer
file. This is the minimum configuration required to get started with load balancing:upstream backend { server srv1.example.com; server srv2.example.com; server 192.168.1.12:8080; # other servers if any } server { listen 80; location / { proxy_pass http://backend; } }
- Enable this configuration by creating a symlink to
load_balancer
undersites-enabled
:$ sudo ln -s /etc/nginx/sites-available/load_balancer /etc/nginx/sites-enabled/load_balancer
- You may want to disable all other sites. Simply remove the respective links under
sites-enabled
. - Check the configuration for syntax errors:
$ sudo nginx -t
- Now, reload Nginx for the changes to take effect:
$ sudo service nginx reload
- Yes, you are ready to use a load balancer. Open your favorite browser and point it to the IP of your Nginx server. You should see the contents of
example.com
or whatever domain you have used.
How it works…
We have created a very basic configuration for a load balancer. With this configuration, Nginx takes the traffic on port 80
and distributes it between srv1.example.com
and srv2.example.com
. With an upstream directive, we have defined a pool of servers that will actually process the requests. The upstream directive must be defined in a HTTP context. Once the upstream directive is defined, it will be available for all site configurations.
Note
All configuration files defined under sites-available
are combined in the main configuration file, /etc/nginx/nginx.conf
, under the HTTP
directive. This enables us to set other directives in site-specific
configurations without specifying the HTTP
block.
When defining servers under an upstream
directive, you can also use the IP address and port of the application server. This is an ideal configuration, especially when both the load balancer and the application servers are on the same private network, and this will help minimize the communication overhead between Nginx and backend servers.
Next, under the server
block, we have configured Nginx to proxy_pass
all requests to our backend
pool.
While setting backend servers, we have not explicitly specified any load balancing algorithm. Nginx provides various load balancing algorithms that define the server that will receive a particular request. By default, Nginx uses a round-robin algorithm and passes requests to each available server in sequential order. Other available options are as follows:
least_connection
: This passes the request to the host with the fewest active connections.least_time
: Nginx chooses the host with the lowest latency. This option is available with Nginx plus.ip_hash
: A hash of clients' IP addresses, and is used to determined the host to send the request to. This method guarantees that requests with the same IP address are served by the same host, unless the selected host is down.
Hash uses a user defined key to generate a hash value and then uses the hash to determine the processing host.
There's more…
Nginx provides various other load balancing features, such as weighted load balancing, active and passive health checks, backup servers, and session persistence. With the latest commits to the open source version, it now supports TCP load balancing as well. These settings can be updated at runtime with the help of HTTP APIs. The following are a few examples of different load balancing configurations:
- Set server weights:
upstream app-servers { server srv1.example.com weight 3; server srv2.example.com; }
- Health checkups and backup servers:
upstream app-servers { server srv1.example.com max_fails 3 fail_timeout 10; server srv2.example.com fail_timeout 50; 192.168.1.12:8080 backup; }
- Session persistence with cookies:
upstream app-servers { server srv1.example.com; server srv2.example.com; sticky cookie srv_id expires=1h domain=.example.com path=/; }
Check the Nginx load balancing guide for various other load balancing options and their respective details.
See also
- Nginx admin guide for load balancers at https://www.nginx.com/resources/admin-guide/load-balancer