Post

HAProxy Ep 6: Load Balancing With Least Connection

HAProxy Ep 6: Load Balancing With Least Connection

{% raw %}

Load balancing is crucial for distributing incoming network traffic across multiple servers, ensuring optimal resource utilization and improving application performance. One of the simplest and most popular load balancing algorithms is Round Robin. In this blog, we’ll explore how to implement Least Connection load balancing using Flask as our backend application and HAProxy as our load balancer.

What is Least Connection Load Balancing?

Least Connection Load Balancing is a dynamic algorithm that distributes requests to the server with the fewest active connections at any given time. This method ensures that servers with lighter loads receive more requests, preventing any single server from becoming a bottleneck.

Step-by-Step Implementation with Docker

Step 1: Create Dockerfiles for Each Flask Application

We’ll create three separate Dockerfiles, one for each Flask app.

Flask App 1 (app1.py) – Introduced Slowness by adding sleep

from flask import Flaskimport timeapp = Flask(__name__)@app.route("/")def hello():    time.sleep(5)    return "Hello from Flask App 1!"if __name__ == "__main__":    app.run(host="0.0.0.0", port=5001)

Flask App 2 (app2.py)

from flask import Flaskapp = Flask(__name__)@app.route("/")def hello():    return "Hello from Flask App 2!"if __name__ == "__main__":    app.run(host="0.0.0.0", port=5002)

Flask App 3 (app3.py) – Introduced Slowness by adding sleep.

from flask import Flaskimport timeapp = Flask(__name__)@app.route("/")def hello():    time.sleep(5)    return "Hello from Flask App 3!"if __name__ == "__main__":    app.run(host="0.0.0.0", port=5003)

Each Flask app listens on a different port (5001, 5002, 5003).

Step 2: Dockerfiles for each flask application

Dockerfile for Flask App 1 (Dockerfile.app1)

# Use the official Python image from the Docker HubFROM python:3.9-slim# Set the working directory inside the containerWORKDIR /app# Copy the current directory contents into the container at /appCOPY 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 configuration for HAProxy

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 leastconn    server server1 app1:5001 check    server server2 app2:5002 check    server server3 app3:5003 check

Explanation:

  • frontend http_front: Defines the entry point for incoming traffic. It listens on port 80.
  • backend servers: Specifies the servers HAProxy will distribute traffic evenly the three Flask apps (app1, app2, app3). The balance leastconn directive sets the Least Connection for load balancing.
  • server directives: Lists the backend servers with their IP addresses and ports. The check option allows HAProxy to monitor the health of each server.

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 Dockercompose 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 four services: app1, app2, app3, and haproxy.
  • Each Flask app is built from its respective Dockerfile and runs on its port.
  • HAProxy is configured to wait (depends_on) for all three Flask apps to be up and running.

Step 6: Build and Run the Docker Containers

Run the following commands to build and start all the containers:

# Build and run the containersdocker-compose up --build

This command will build Docker images for all three Flask apps and HAProxy and start them up in the background.

You should see the responses alternating between “Hello from Flask App 1!”, “Hello from Flask App 2!”, and “Hello from Flask App 3!” as HAProxy uses the Round Robin algorithm to distribute requests.

Step 7: Test the Load Balancer

Open your browser or use a tool like curl to make requests to the HAProxy server:

curl http://localhost

You should see responses cycling between “Hello from Flask App 1!”, “Hello from Flask App 2!”, and “Hello from Flask App 3!” according to the Least Connection strategy.

{% endraw %}

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