Hone logo
Hone
Problems

Implementing a Simple Round-Robin Load Balancer

This challenge involves creating a basic load balancer in Python. Load balancing is a crucial technique for distributing network traffic across multiple servers to ensure no single server becomes overwhelmed. This exercise will help you understand the fundamental principles of load balancing.

Problem Description

You need to implement a LoadBalancer class that manages a list of available servers and distributes incoming requests among them using a round-robin strategy. The LoadBalancer should keep track of the next server to assign a request to and cycle through the available servers.

Key Requirements:

  • The LoadBalancer should be initialized with a list of server identifiers (e.g., IP addresses or hostnames).
  • A method get_next_server() should be implemented. This method should return the identifier of the next server in line to handle a request.
  • The selection of servers must follow a strict round-robin pattern. When the last server in the list has been selected, the next request should go to the first server again.
  • If there are no servers available, get_next_server() should return None.
  • The LoadBalancer should also support adding and removing servers dynamically.

Expected Behavior:

When get_next_server() is called repeatedly, it should iterate through the servers in the order they were provided, and then loop back to the beginning.

Edge Cases:

  • Initializing the load balancer with an empty list of servers.
  • Calling get_next_server() when no servers are available.
  • Adding servers when the load balancer is empty.
  • Removing the last remaining server.

Examples

Example 1:

servers = ["192.168.1.100", "192.168.1.101", "192.168.1.102"]
lb = LoadBalancer(servers)

print(lb.get_next_server()) # Output: 192.168.1.100
print(lb.get_next_server()) # Output: 192.168.1.101
print(lb.get_next_server()) # Output: 192.168.1.102
print(lb.get_next_server()) # Output: 192.168.1.100
print(lb.get_next_server()) # Output: 192.168.1.101

Explanation: The requests are distributed sequentially. After the last server is used, the cycle restarts from the first server.

Example 2:

servers = ["serverA", "serverB"]
lb = LoadBalancer(servers)

lb.remove_server("serverA")
print(lb.get_next_server()) # Output: serverB
print(lb.get_next_server()) # Output: serverB

Explanation: After removing "serverA", only "serverB" remains, so all subsequent requests are directed to it.

Example 3:

servers = []
lb = LoadBalancer(servers)

print(lb.get_next_server()) # Output: None

lb.add_server("localhost")
print(lb.get_next_server()) # Output: localhost
print(lb.get_next_server()) # Output: localhost

Explanation: Initially, no servers are available. After adding "localhost", it becomes the sole server for subsequent requests.

Constraints

  • The number of initial servers will be between 0 and 1000.
  • Server identifiers will be strings.
  • The get_next_server() method should be efficient, ideally O(1) complexity.
  • Adding and removing servers should also be efficient, ideally O(1) or O(N) where N is the number of servers.

Notes

Consider how to efficiently manage the index of the next server to be selected. Think about what data structures would be suitable for storing the servers and for tracking the current position in the round-robin cycle. You might want to use a list or a deque for storing servers. Remember to handle the case where the server list becomes empty or a server is removed.

Loading editor...
python