HAProxy EP 8: Load Balancing with Random Load Balancing
Load balancing distributes client requests across multiple servers to ensure high availability and reliability. One of the simplest load balancing algorithms is Random Load Balancing, which selects a backend server randomly for each client request.
Although this approach does not consider server load or other metrics, it can be effective for less critical applications or when the goal is to achieve simplicity.
What is Random Load Balancing?
Random Load Balancing assigns incoming requests to a randomly chosen server from the available pool of servers. This method is straightforward and ensures that requests are distributed in a non-deterministic manner, which may work well for environments with equally capable servers and minimal concerns about server load or state.
Step-by-Step Implementation with Docker
Step 1: Create Dockerfiles for Each Flask Application
We’ll use the same three Flask applications (app1.py
, app2.py
, and app3.py
) as in previous examples.
Flask App 1 – (app.py)
from flask import Flask app = Flask(__name__) @app.route("/") def home(): return "Hello from Flask App 1!" @app.route("/data") def data(): return "Data from Flask App 1!" if __name__ == "__main__": app.run(host="0.0.0.0", port=5001)
Flask App 2 – (app.py)
from flask import Flask app = Flask(__name__) @app.route("/") def home(): return "Hello from Flask App 2!" @app.route("/data") def data(): return "Data from Flask App 2!" if __name__ == "__main__": app.run(host="0.0.0.0", port=5002)
Flask App 3 – (app.py)
from flask import Flask app = Flask(__name__) @app.route("/") def home(): return "Hello from Flask App 3!" @app.route("/data") def data(): return "Data from Flask App 3!" if __name__ == "__main__": app.run(host="0.0.0.0", port=5003)
Step 2: Create Dockerfiles for Each Flask Application
Create Dockerfiles for each of the Flask applications:
- Dockerfile for Flask App 1 (
Dockerfile.app1
):
# Use the official Python image from Docker Hub FROM python:3.9-slim # Set the working directory inside the container WORKDIR /app # Copy the application file into the container COPY app1.py . # Install Flask inside the container RUN pip install Flask # Expose the port the app runs on EXPOSE 5001 # Run the application CMD ["python", "app1.py"]
- Dockerfile for Flask App 2 (
Dockerfile.app2
):
FROM python:3.9-slim WORKDIR /app COPY app2.py . RUN pip install Flask EXPOSE 5002 CMD ["python", "app2.py"]
- Dockerfile for Flask App 3 (
Dockerfile.app3
):
FROM python:3.9-slim WORKDIR /app COPY app3.py . RUN pip install Flask EXPOSE 5003 CMD ["python", "app3.py"]
Step 3: Create a Dockerfile for HAProxy
HAProxy Configuration file,
global log stdout format raw local0 daemon defaults log global mode http option httplog option dontlognull timeout connect 5000ms timeout client 50000ms timeout server 50000ms frontend http_front bind *:80 default_backend servers backend servers balance random random draw 2 server server1 app1:5001 check server server2 app2:5002 check server server3 app3:5003 check
Explanation:
- The
balance random
directive tells HAProxy to use the Random load balancing algorithm. - The
random draw 2
setting makes HAProxy select 2 servers randomly and choose the one with the least number of connections. This adds a bit of load awareness to the random choice. - The
server
directives define the backend servers and their ports.
Step 4: Create a Dockerfile for HAProxy
Create a Dockerfile for HAProxy (Dockerfile.haproxy
):
# Use the official HAProxy image from Docker Hub FROM haproxy:latest # Copy the custom HAProxy configuration file into the container COPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg # Expose the port for HAProxy EXPOSE 80
Step 5: Create a docker-compose.yml
File
To manage all the containers together, create a docker-compose.yml
file:
version: '3' services: app1: build: context: . dockerfile: Dockerfile.app1 container_name: flask_app1 ports: - "5001:5001" app2: build: context: . dockerfile: Dockerfile.app2 container_name: flask_app2 ports: - "5002:5002" app3: build: context: . dockerfile: Dockerfile.app3 container_name: flask_app3 ports: - "5003:5003" haproxy: build: context: . dockerfile: Dockerfile.haproxy container_name: haproxy ports: - "80:80" depends_on: - app1 - app2 - app3
Explanation:
- The
docker-compose.yml
file defines the services (app1
,app2
,app3
, andhaproxy
) and their respective configurations. - HAProxy depends on the three Flask applications to be up and running before it starts.
Step 6: Build and Run the Docker Containers
Run the following command to build and start all the containers:
docker-compose up --build
This command builds Docker images for all three Flask apps and HAProxy, then starts them.
Step 7: Test the Load Balancer
Open your browser or use curl
to make requests to the HAProxy server:
curl http://localhost/ curl http://localhost/data
Observation:
- With Random Load Balancing, each request should randomly hit one of the three backend servers.
- Since the selection is random, you may not see a predictable pattern; however, the requests should be evenly distributed across the servers over a large number of requests.
Conclusion
By implementing Random Load Balancing with HAProxy, we’ve demonstrated a simple way to distribute traffic across multiple servers without relying on complex metrics or state information. While this approach may not be ideal for all use cases, it can be useful in scenarios where simplicity is more valuable than fine-tuned load distribution.