Post

HAProxy EP 8: Load Balancing with Random Load Balancing

HAProxy EP 8: Load Balancing with Random Load Balancing

{% raw %}

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 Flaskapp = 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 Flaskapp = 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 Flaskapp = 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 HubFROM python:3.9-slim# Set the working directory inside the containerWORKDIR /app# Copy the application file into the containerCOPY app1.py .# Install Flask inside the containerRUN pip install Flask# Expose the port the app runs onEXPOSE 5001# Run the applicationCMD ["python", "app1.py"]
  • Dockerfile for Flask App 2 (Dockerfile.app2):
FROM python:3.9-slimWORKDIR /appCOPY app2.py .RUN pip install FlaskEXPOSE 5002CMD ["python", "app2.py"]
  • Dockerfile for Flask App 3 (Dockerfile.app3):
FROM python:3.9-slimWORKDIR /appCOPY app3.py .RUN pip install FlaskEXPOSE 5003CMD ["python", "app3.py"]

Step 3: Create a Dockerfile for HAProxy

HAProxy Configuration file,

global    log stdout format raw local0    daemondefaults    log     global    mode    http    option  httplog    option  dontlognull    timeout connect 5000ms    timeout client  50000ms    timeout server  50000msfrontend http_front    bind *:80    default_backend serversbackend 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 HubFROM haproxy:latest# Copy the custom HAProxy configuration file into the containerCOPY haproxy.cfg /usr/local/etc/haproxy/haproxy.cfg# Expose the port for HAProxyEXPOSE 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, and haproxy) 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.

{% endraw %}

This post is licensed under CC BY 4.0 by the author.