Static Load Balancing Algorithms

Last Updated : 27 Jan, 2026

Static load balancing assigns tasks to servers using predefined rules, without considering real-time system conditions.

  • Workloads are allocated in a fixed and predetermined manner.
  • Does not adapt to changes during runtime.
  • Suitable for stable environments with predictable workloads.

Types of Static Load Balancing Algorithms are:

  1. Round Robin Load Balancing Algorithm
  2. Weighted Round Robin Load Balancing Algorithm
  3. Source IP Hash Load Balancing Algorithm

1. Round Robin Load Balancing Algorithm

Round Robin is a simple static load balancing technique that distributes incoming requests to servers in a fixed sequential or rotational order. It is commonly used due to its ease of implementation.

  • Requests are assigned to servers one by one in a circular manner.
  • Does not consider current server load, which may cause some servers to become overloaded.

For Example: Lets say you have a group of friends, and you want to share a bag of candies equally with all of them. You give one candy to each friend in a circle, and then you start over. This is like Round Robin – making sure everyone gets a fair share.

load_balancer
Round Robin

Implementing the Round Robin Load Balancing Algorithm

The goal of this implementation is to evenly distribute incoming requests across a list of servers using a fixed sequential order.

  • The first request is routed to the first server.
  • Each subsequent request is sent to the next server in the list.
  • After the last server, the distribution loops back to the first server.
C++
#include <iostream>
#include <vector>
#include <string>

class LoadBalancer {
private:
    std::vector<std::string> servers;
    int currentIndex;

public:
    LoadBalancer(std::vector<std::string> servers) : servers(servers), currentIndex(0) {}

    std::string getNextServer() {
        std::string nextServer = servers[currentIndex];
        currentIndex = (currentIndex + 1) % servers.size();
        return nextServer;
    }
};

int main() {
    // Sample list of servers
    std::vector<std::string> serverList = {"Server1", "Server2", "Server3"};

    // Create a load balancer with the server list
    LoadBalancer loadBalancer(serverList);

    // Simulate requests to the load balancer
    for (int i = 0; i < 10; i++) {
        std::string nextServer = loadBalancer.getNextServer();
        std::cout << "Request " << (i + 1) << ": Routed to " << nextServer << std::endl;
    }

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

class LoadBalancer {
    private List<String> servers;
    private int currentIndex;

    public LoadBalancer(List<String> servers) {
        this.servers = new ArrayList<>(servers);
        this.currentIndex = 0;
    }

    public String getNextServer() {
        String nextServer = servers.get(currentIndex);
        currentIndex = (currentIndex + 1) % servers.size();
        return nextServer;
    }
}

public class RoundRobinExample {
    public static void main(String[] args) {
        // Sample list of servers
        List<String> serverList = new ArrayList<>();
        serverList.add("Server1");
        serverList.add("Server2");
        serverList.add("Server3");

        // Create a load balancer with the server list
        LoadBalancer loadBalancer = new LoadBalancer(serverList);

        // Simulate requests to the load balancer
        for (int i = 0; i < 10; i++) {
            String nextServer = loadBalancer.getNextServer();
            System.out.println("Request " + (i + 1) + ": Routed to " + nextServer);
        }
    }
}
Python
class LoadBalancer:
    def __init__(self, servers):
        self.servers = servers
        self.currentIndex = 0

    def getNextServer(self):
        nextServer = self.servers[self.currentIndex]
        self.currentIndex = (self.currentIndex + 1) % len(self.servers)
        return nextServer

if __name__ == "__main__":
    # Sample list of servers
    serverList = ["Server1", "Server2", "Server3"]

    # Create a load balancer with the server list
    loadBalancer = LoadBalancer(serverList)

    # Simulate requests to the load balancer
    for i in range(10):
        nextServer = loadBalancer.getNextServer()
        print(f'Request {i + 1}: Routed to {nextServer}')
JavaScript
class LoadBalancer {
    constructor(servers) {
        this.servers = servers;
        this.currentIndex = 0;
    }

    getNextServer() {
        const nextServer = this.servers[this.currentIndex];
        this.currentIndex = (this.currentIndex + 1) % this.servers.length;
        return nextServer;
    }
}

// Sample list of servers
const serverList = ["Server1", "Server2", "Server3"];

// Create a load balancer with the server list
const loadBalancer = new LoadBalancer(serverList);

// Simulate requests to the load balancer
for (let i = 0; i < 10; i++) {
    const nextServer = loadBalancer.getNextServer();
    console.log(`Request ${i + 1}: Routed to ${nextServer}`);
}

Output
Request 1: Routed to Server1
Request 2: Routed to Server2
Request 3: Routed to Server3
Request 4: Routed to Server1
Request 5: Routed to Server2
Request 6: Routed to Server3
Request 7: Routed to Serve...
  • The LoadBalancer class stores server names and selects the next server using a round-robin approach.
  • It tracks the current index to ensure requests are evenly distributed.
  • The RoundRobinExample class initializes the load balancer with a list of servers.
  • Multiple requests are simulated by calling getNextServer() and printing the selected server.

When to use Round Robin Load Balancing Algorithm

Round Robin load balancing is best used in simple environments where requests need to be distributed evenly across servers.

  • Suitable when all servers have similar capacity and performance.
  • Works well for evenly distributed workloads such as basic web requests.
  • Best for simple architectures without complex resource requirements.
  • Ideal when balanced distribution matters more than request order.

Benefits and Drawbacks of Round Robin Load Balancing Algorithm

Round Robin load balancing offers a straightforward way to distribute requests but may fall short in more complex environments.

Benefits: These advantages make Round Robin a simple and fair load-balancing strategy for basic systems.

  • Simplicity: Easy to implement and understand.
  • Fairness: Ensures each server receives an equal share of requests.

Drawbacks: These limitations can affect performance in more complex or uneven server environments.

  • Unequal Capacities: Treats all servers equally without considering differences in performance or capacity.
  • Predictability: Not optimal for systems with heterogeneous server resources.

2. Weighted Round Robin Load Balancing Algorithm

Weighted Round Robin is a static load balancing technique similar to Round Robin, but it distributes requests based on assigned weight values that represent each server’s capacity.

  • Servers with higher weights receive a larger share of requests.
  • Requests are distributed in a cyclic manner, proportional to each server’s weight.
  • If a server reaches its capacity, it may queue or reject additional requests based on its behavior.

For Example: let's say your friends have different levels of candy cravings. You want to be fair, so you give more candies to the friend who loves them the most. Weighted Round Robin does something similar – it gives more tasks to the friends who can handle them better.

Three servers are assigned weights: Server1 (0.3), Server2 (0.2), and Server3 (0.1).

  • The total weight is 0.6 (0.3 + 0.2 + 0.1).
  • Server1 receives 50% of the requests (0.3 / 0.6).
  • Server2 receives 33.33% of the requests (0.2 / 0.6).
  • Server3 receives 16.67% of the requests (0.1 / 0.6).
load_balancer-1
Weighted Round Robin

Implementing the Weighted Round Robin Load Balancing Algorithm

It allows requests to be distributed across servers based on assigned weights, ensuring more capable servers handle a higher share of the traffic.

C++
#include <iostream>
#include <vector>
#include <cstdlib>
#include <ctime>

class Server {
public:
    std::string name;
    int weight;

    Server(std::string name, int weight) {
        this->name = name;
        this->weight = weight;
    }
};

class WeightedRoundRobinBalancer {
private:
    std::vector<Server> servers;
    std::vector<int> cumulativeWeights;
    int totalWeight;
    int currentIndex;

public:
    WeightedRoundRobinBalancer(std::vector<Server> servers) {
        this->servers = servers;
        this->totalWeight = calculateTotalWeight(servers);
        this->cumulativeWeights = calculateCumulativeWeights(servers);
        this->currentIndex = 0;
        srand(time(0));
    }

    int calculateTotalWeight(std::vector<Server> servers) {
        int totalWeight = 0;
        for (Server server : servers) {
            totalWeight += server.weight;
        }
        return totalWeight;
    }

    std::vector<int> calculateCumulativeWeights(std::vector<Server> servers) {
        std::vector<int> cumulativeWeights(servers.size());
        cumulativeWeights[0] = servers[0].weight;
        for (int i = 1; i < servers.size(); i++) {
            cumulativeWeights[i] = cumulativeWeights[i - 1] + servers[i].weight;
        }
        return cumulativeWeights;
    }

    Server getNextServer() {
        int randomValue = rand() % totalWeight;
        for (int i = 0; i < cumulativeWeights.size(); i++) {
            if (randomValue < cumulativeWeights[i]) {
                currentIndex = i;
                break;
            }
        }
        return servers[currentIndex];
    }
};

int main() {
    // Sample list of servers with weights
    std::vector<Server> serverList = {Server("Server1", 3), Server("Server2", 2), Server("Server3", 1)};

    // Create a weighted round-robin load balancer with the server list
    WeightedRoundRobinBalancer balancer(serverList);

    // Simulate requests to the load balancer
    for (int i = 0; i < 10; i++) {
        Server nextServer = balancer.getNextServer();
        std::cout << "Request " << (i + 1) << ": Routed to " << nextServer.name << std::endl;
    }

    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

class WeightedRoundRobinBalancer {
    private List<Server> servers;
    private int[] cumulativeWeights;
    private int totalWeight;
    private int currentIndex;
    private Random random;

    public WeightedRoundRobinBalancer(List<Server> servers) {
        this.servers = new ArrayList<>(servers);
        this.totalWeight = calculateTotalWeight(servers);
        this.cumulativeWeights = calculateCumulativeWeights(servers);
        this.currentIndex = 0;
        this.random = new Random();
    }

    private int calculateTotalWeight(List<Server> servers) {
        int totalWeight = 0;
        for (Server server : servers) {
            totalWeight += server.getWeight();
        }
        return totalWeight;
    }

    private int[] calculateCumulativeWeights(List<Server> servers) {
        int[] cumulativeWeights = new int[servers.size()];
        cumulativeWeights[0] = servers.get(0).getWeight();
        for (int i = 1; i < servers.size(); i++) {
            cumulativeWeights[i] = cumulativeWeights[i - 1] + servers.get(i).getWeight();
        }
        return cumulativeWeights;
    }

    public Server getNextServer() {
        int randomValue = random.nextInt(totalWeight);
        for (int i = 0; i < cumulativeWeights.length; i++) {
            if (randomValue < cumulativeWeights[i]) {
                currentIndex = i;
                break;
            }
        }
        return servers.get(currentIndex);
    }

    // Inner class representing a server with a weight
    static class Server {
        private String name;
        private int weight;

        public Server(String name, int weight) {
            this.name = name;
            this.weight = weight;
        }

        public String getName() {
            return name;
        }

        public int getWeight() {
            return weight;
        }
    }
}

public class WeightedRoundRobinExample {
    public static void main(String[] args) {
        // Sample list of servers with weights
        List<WeightedRoundRobinBalancer.Server> serverList = new ArrayList<>();
        serverList.add(new WeightedRoundRobinBalancer.Server("Server1", 3));
        serverList.add(new WeightedRoundRobinBalancer.Server("Server2", 2));
        serverList.add(new WeightedRoundRobinBalancer.Server("Server3", 1));

        // Create a weighted round-robin load balancer with the server list
        WeightedRoundRobinBalancer balancer = new WeightedRoundRobinBalancer(serverList);

        // Simulate requests to the load balancer
        for (int i = 0; i < 10; i++) {
            WeightedRoundRobinBalancer.Server nextServer = balancer.getNextServer();
            System.out.println("Request " + (i + 1) + ": Routed to " + nextServer.getName());
        }
    }
}
Python
import random

class Server:
    def __init__(self, name, weight):
        self.name = name
        self.weight = weight

    def get_name(self):
        return self.name

    def get_weight(self):
        return self.weight

class WeightedRoundRobinBalancer:
    def __init__(self, servers):
        self.servers = servers
        self.total_weight = self.calculate_total_weight(servers)
        self.cumulative_weights = self.calculate_cumulative_weights(servers)
        self.current_index = 0
        self.random = random.Random()

    def calculate_total_weight(self, servers):
        total_weight = 0
        for server in servers:
            total_weight += server.get_weight()
        return total_weight

    def calculate_cumulative_weights(self, servers):
        cumulative_weights = [0] * len(servers)
        cumulative_weights[0] = servers[0].get_weight()
        for i in range(1, len(servers)):
            cumulative_weights[i] = cumulative_weights[i - 1] + servers[i].get_weight()
        return cumulative_weights

    def get_next_server(self):
        random_value = self.random.randint(0, self.total_weight - 1)
        for i in range(len(self.cumulative_weights)):
            if random_value < self.cumulative_weights[i]:
                self.current_index = i
                break
        return self.servers[self.current_index]


if __name__ == "__main__":
    # Sample list of servers with weights
    server_list = [
        Server("Server1", 3),
        Server("Server2", 2),
        Server("Server3", 1)
    ]

    # Create a weighted round-robin load balancer with the server list
    balancer = WeightedRoundRobinBalancer(server_list)

    # Simulate requests to the load balancer
    for i in range(10):
        next_server = balancer.get_next_server()
        print(f"Request {i + 1}: Routed to {next_server.get_name()}")
JavaScript
class Server {
    constructor(name, weight) {
        this.name = name;
        this.weight = weight;
    }

    getName() {
        return this.name;
    }

    getWeight() {
        return this.weight;
    }
}

class WeightedRoundRobinBalancer {
    constructor(servers) {
        this.servers = servers;
        this.totalWeight = this.calculateTotalWeight(servers);
        this.cumulativeWeights = this.calculateCumulativeWeights(servers);
        this.currentIndex = 0;
        this.random = Math.random;
    }

    calculateTotalWeight(servers) {
        let totalWeight = 0;
        for (let server of servers) {
            totalWeight += server.getWeight();
        }
        return totalWeight;
    }

    calculateCumulativeWeights(servers) {
        let cumulativeWeights = new Array(servers.length).fill(0);
        cumulativeWeights[0] = servers[0].getWeight();
        for (let i = 1; i < servers.length; i++) {
            cumulativeWeights[i] = cumulativeWeights[i - 1] + servers[i].getWeight();
        }
        return cumulativeWeights;
    }

    getNextServer() {
        let randomValue = Math.floor(this.random() * this.totalWeight);
        for (let i = 0; i < this.cumulativeWeights.length; i++) {
            if (randomValue < this.cumulativeWeights[i]) {
                this.currentIndex = i;
                break;
            }
        }
        return this.servers[this.currentIndex];
    }
}

// Sample list of servers with weights
let serverList = [
    new Server("Server1", 3),
    new Server("Server2", 2),
    new Server("Server3", 1)
];

// Create a weighted round-robin load balancer with the server list
let balancer = new WeightedRoundRobinBalancer(serverList);

// Simulate requests to the load balancer
for (let i = 0; i < 10; i++) {
    let nextServer = balancer.getNextServer();
    console.log(`Request ${i + 1}: Routed to ${nextServer.getName()}`);
}

Output
Request 1: Routed to Server2
Request 2: Routed to Server2
Request 3: Routed to Server1
Request 4: Routed to Server2
Request 5: Routed to Server1
Request 6: Routed to Server2
Request 7: Routed to Serve...
  • The WeightedRoundRobinBalancer maintains a list of servers along with their assigned weights.
  • It calculates total and cumulative weights to select the next server using weighted round-robin.
  • An inner Server class represents each server with its name and weight.
  • The example class simulates requests and prints the server handling each request.

Use Cases for Weighted Round Robin Algorithm

Weighted Round Robin is best used when servers have different capacities and workloads need to be distributed accordingly.

  • Suitable when servers have varying performance or capacity levels.
  • Ideal for environments with different hardware resources (CPU, memory, etc.).
  • Helps maximize overall resource utilization.
  • Prevents overloading smaller servers while efficiently using larger ones.

Benefits and Drawbacks of Weighted Round Robin Algorithm

Weighted Round Robin improves load distribution by considering server capacity, but it also introduces additional complexity.

Benefits: These advantages make Weighted Round Robin suitable for environments with servers of different capacities.

  • Capacity Consideration: Accounts for different server capacities by assigning weights.
  • Flexibility: Can be adjusted to handle varying workloads effectively.

Drawbacks: These limitations highlight the additional effort required to manage the algorithm effectively.

  • Complexity: More complex to implement than simple Round Robin.
  • Maintenance: Requires regular weight adjustments as server capacities change.

3. Source IP Hash Load Balancing Algorithm

The Source IP Hash Load Balancing Algorithm distributes incoming requests by computing a hash of the client’s source IP address. This approach helps route requests from the same client to the same backend server consistently.

  • Uses the source IP address to calculate a hash and select a server.
  • Ensures request consistency by mapping the same IP to the same server.
  • Enables session persistence, making it suitable for stateful applications.

For Example: Think of your friends coming to your house, and you want to remember who gets which toy every time they visit. IP Hash is like remembering which friend played with which toy last time, so you always give them the same one.

load_balancer-2
IP Hash

Implementation the Source IP Hash Load Balancing Algorithms:

A load balancing algorithm distributes incoming requests using a hash of the source IP address to ensure consistent server selection.

  • Routes requests from the same source IP to the same backend server
  • Helps maintain session consistency for stateful applications.
C++
#include <iostream>
#include <unordered_map>
#include <vector>
#include <string>
#include <cstdlib>

class SourceIpHashLoadBalancer {
private:
    std::unordered_map<std::string, std::string> ipToServerMap;

public:
    SourceIpHashLoadBalancer() {}

    void addServer(const std::string& serverName) {
        // Add server to the mapping
        ipToServerMap[serverName] = serverName;
    }

    std::string getServerForIp(const std::string& sourceIp) {
        // Calculate hash of the source IP
        size_t hash = std::hash<std::string>{}(sourceIp);

        // Get the list of available servers
        std::vector<std::string> servers(ipToServerMap.size());
        size_t i = 0;
        for (const auto& pair : ipToServerMap) {
            servers[i++] = pair.first;
        }

        // Map the hash value to a server index
        size_t serverIndex = hash % servers.size();

        // Return the selected server
        return servers[serverIndex];
    }
};

int main() {
    // Create a source IP hash load balancer
    SourceIpHashLoadBalancer loadBalancer;

    // Add servers to the load balancer
    loadBalancer.addServer("Server1");
    loadBalancer.addServer("Server2");
    loadBalancer.addServer("Server3");

    // Simulate requests with different source IPs
    std::vector<std::string> sourceIps = {"192.168.1.1", "10.0.0.1", "172.16.0.1"};

    for (const std::string& sourceIp : sourceIps) {
        std::string selectedServer = loadBalancer.getServerForIp(sourceIp);
        std::cout << "Request from " << sourceIp << " routed to " << selectedServer << std::endl;
    }

    return 0;
}
Java
import java.util.HashMap;
import java.util.Map;

class SourceIpHashLoadBalancer {
    private Map<String, String> ipToServerMap;

    public SourceIpHashLoadBalancer() {
        this.ipToServerMap = new HashMap<>();
    }

    public void addServer(String serverName) {
        // Add server to the mapping
        ipToServerMap.put(serverName, serverName);
    }

    public String getServerForIp(String sourceIp) {
        // Calculate hash of the source IP
        int hash = sourceIp.hashCode();

        // Get the list of available servers
        String[] servers = ipToServerMap.keySet().toArray(new String[0]);

        // Map the hash value to a server index
        int serverIndex = Math.abs(hash) % servers.length;

        // Return the selected server
        return servers[serverIndex];
    }
}

public class SourceIpHashLoadBalancerExample {
    public static void main(String[] args) {
        // Create a source IP hash load balancer
        SourceIpHashLoadBalancer loadBalancer = new SourceIpHashLoadBalancer();

        // Add servers to the load balancer
        loadBalancer.addServer("Server1");
        loadBalancer.addServer("Server2");
        loadBalancer.addServer("Server3");

        // Simulate requests with different source IPs
        String[] sourceIps = {"192.168.1.1", "10.0.0.1", "172.16.0.1"};

        for (String sourceIp : sourceIps) {
            String selectedServer = loadBalancer.getServerForIp(sourceIp);
            System.out.println("Request from " + sourceIp + " routed to " + selectedServer);
        }
    }
}
Python
class SourceIpHashLoadBalancer:
    def __init__(self):
        self.ip_to_server_map = {}

    def add_server(self, server_name):
        # Add server to the mapping
        self.ip_to_server_map[server_name] = server_name

    def get_server_for_ip(self, source_ip):
        # Calculate hash of the source IP
        hash_value = hash(source_ip)

        # Get the list of available servers
        servers = list(self.ip_to_server_map.keys())

        # Map the hash value to a server index
        server_index = abs(hash_value) % len(servers)

        # Return the selected server
        return servers[server_index]

# Create a source IP hash load balancer
load_balancer = SourceIpHashLoadBalancer()

# Add servers to the load balancer
load_balancer.add_server("Server1")
load_balancer.add_server("Server2")
load_balancer.add_server("Server3")

# Simulate requests with different source IPs
source_ips = ["192.168.1.1", "10.0.0.1", "172.16.0.1"]

for source_ip in source_ips:
    selected_server = load_balancer.get_server_for_ip(source_ip)
    print(f'Request from {source_ip} routed to {selected_server}')
JavaScript
class SourceIpHashLoadBalancer {
    constructor() {
        this.ipToServerMap = new Map();
    }

    addServer(serverName) {
        // Add server to the mapping
        this.ipToServerMap.set(serverName, serverName);
    }

    getServerForIp(sourceIp) {
        // Calculate hash of the source IP
        let hash = sourceIp.split('').reduce((a,b) => a + b.charCodeAt(0), 0);

        // Get the list of available servers
        let servers = Array.from(this.ipToServerMap.keys());

        // Map the hash value to a server index
        let serverIndex = Math.abs(hash) % servers.length;

        // Return the selected server
        return servers[serverIndex];
    }
}

function SourceIpHashLoadBalancerExample() {
    // Create a source IP hash load balancer
    let loadBalancer = new SourceIpHashLoadBalancer();

    // Add servers to the load balancer
    loadBalancer.addServer("Server1");
    loadBalancer.addServer("Server2");
    loadBalancer.addServer("Server3");

    // Simulate requests with different source IPs
    let sourceIps = ["192.168.1.1", "10.0.0.1", "172.16.0.1"];

    for (let sourceIp of sourceIps) {
        let selectedServer = loadBalancer.getServerForIp(sourceIp);
        console.log(`Request from ${sourceIp} routed to ${selectedServer}`);
    }
}

SourceIpHashLoadBalancerExample();

Output
Request from 192.168.1.1 routed to Server2
Request from 10.0.0.1 routed to Server1
Request from 172.16.0.1 routed to Server3
  • Defines a SourceIpHashLoadBalancer class that maps source IPs to servers using hashing.
  • Maintains an ipToServerMap to ensure consistent IP-to-server mapping.
  • Provides methods to add servers and determine the server for a given source IP.
  • Demonstrates usage by adding servers and simulating requests from different source IPs.

Use Cases for Source IP Hash Algorithm

Source IP Hash Load Balancing is commonly used in scenarios where consistent request routing is required based on the client’s IP address.

  • Ideal for applications requiring session consistency, such as online banking, where users must stay connected to the same server.
  • Useful for routing users from specific regions to dedicated servers for performance or compliance needs.
  • Effective when a small number of IPs generate high traffic, ensuring stable load distribution without frequent server switching.

Benefits and Drawbacks of Source IP Hash Algorithm

This algorithm offers consistent request routing based on client IP addresses but comes with trade-offs in flexibility and scalability.

Benefits: Source IP Hash load balancing provides reliable and consistent request routing for clients.

  • Consistency: Routes requests from the same source IP to the same server, maintaining session state.
  • Predictability: Ensures stable and predictable routing when connection persistence is critical.

Drawbacks: While effective for consistency, this approach has limitations in flexibility and scalability.

  • Limited Distribution: Can cause uneven load if some source IPs generate significantly more traffic.
  • Scaling Challenges: Adding or removing servers may break existing client-to-server mappings.
Comment
Article Tags:

Explore