Load Balancing - Algorithms (Round Robin, Least Connections, IP Hash)
Initialize Load Balancer State
The load balancer initializes with three servers: S1, S2, and S3. It sets the round robin index to 0, connection counts to {S1:2, S2:1, S3:3}, and marks all servers as healthy.
self.servers = servers
self.index = 0
self.connections = {server: 0 for server in servers}
self.healthy = {server: True for server in servers}Round Robin: Select Server S1
The load balancer selects the server at index 0 (S1) for the Round Robin algorithm. It checks if S1 is healthy, which it is, so it chooses S1 and increments the index to 1.
server = self.servers[self.index]
self.index = (self.index + 1) % n
if self.healthy[server]:
return serverRound Robin: Skip S2 if Unhealthy (Simulated)
Simulating S2 as unhealthy, the load balancer checks S2 at index 1 but finds it unhealthy, so it skips S2 and moves to the next server.
server = self.servers[self.index]
self.index = (self.index + 1) % n
if self.healthy[server]:
return serverLeast Connections: Identify Healthy Servers
The load balancer filters servers to only those that are healthy. Here, all servers are healthy, so the healthy_servers dictionary includes S1, S2, and S3 with their current connection counts.
healthy_servers = {s: c for s, c in self.connections.items() if self.healthy[s]}Least Connections: Select Server S2
Among healthy servers, the load balancer finds the server with the fewest active connections. S2 has 1 connection, fewer than S1 (2) and S3 (3), so S2 is selected.
return min(healthy_servers, key=healthy_servers.get)IP Hash: Compute Hash for Client IP
The load balancer computes a hash of the client IP '192.168.1.100' to determine the initial server index for IP Hash selection.
idx = (hash(client_ip) + i) % nIP Hash: Check Server at Computed Index
The load balancer checks the server at the computed index (e.g., index 2 → S3). Since S3 is healthy, it selects S3 for routing the client request.
server = self.servers[idx]
if self.healthy[server]:
return serverRound Robin: Increment Index for Next Request
After selecting S1, the Round Robin index is incremented to 1, preparing for the next request to select the next server in order.
self.index = (self.index + 1) % nLeast Connections: Update Connection Count for S2
After selecting S2, the load balancer increments the connection count for S2 to reflect the new active connection.
self.connections[server] += 1Final State: Summary of Server Selections
The load balancer has selected S1 for Round Robin, S2 for Least Connections, and S3 for IP Hash. The internal states reflect these selections and updated indices and counts.
# Final selections returned by each methodclass LoadBalancerDetailed:
def __init__(self, servers): # STEP 1
self.servers = servers
self.index = 0
self.connections = {server: 0 for server in servers}
self.healthy = {server: True for server in servers}
def health_check(self, server, status): # STEP 3
self.healthy[server] = status
def round_robin(self): # STEP 2,8
n = len(self.servers)
for _ in range(n):
server = self.servers[self.index] # select server at current index
self.index = (self.index + 1) % n # increment index
if self.healthy[server]: # check health
return server
return None
def least_connections(self): # STEP 4,5,9
healthy_servers = {s: c for s, c in self.connections.items() if self.healthy[s]} # filter healthy
if not healthy_servers:
return None
server = min(healthy_servers, key=healthy_servers.get) # select least connections
self.connections[server] += 1 # increment connections
return server
def ip_hash(self, client_ip): # STEP 6,7
n = len(self.servers)
for i in range(n):
idx = (hash(client_ip) + i) % n # compute index
server = self.servers[idx]
if self.healthy[server]: # check health
return server
return None
Key Takeaways
This is hard to see from code alone because the index update and health check interplay is subtle.
Visualizing connection counts clarifies how load balancing adapts to server usage.
The hashing and fallback logic is easier to grasp when seen step-by-step.
