Menu
Dev.to #systemdesign·September 5, 2026

Mastering Weighted Round Robin for Load Balancing

This article explores the implementation and benefits of Weighted Round Robin (WRR) load balancing as an improvement over naive round robin. It demonstrates how WRR allows for intelligent distribution of traffic based on server capacity, integrating with health checks to avoid overloading degraded nodes. The discussion highlights WRR's predictability, graceful scaling, and simplicity as key architectural advantages for high-throughput systems.

Read original on Dev.to #systemdesign

The Need for Smarter Load Balancing

Traditional round robin load balancing distributes requests equally among available servers. While simple, this approach often leads to performance bottlenecks when servers have varying capacities, current loads, or are in degraded states. Sending traffic to an overloaded or warming-up server can cause cascading failures and poor user experience, as exemplified by a scenario where an API sputtered under a traffic spike due to a naive load balancer.

Understanding Weighted Round Robin (WRR)

Weighted Round Robin (WRR) is an enhancement that assigns a 'weight' to each server, representing its processing capacity (e.g., based on CPU, memory, or current load score). The load balancer then distributes requests proportionally to these weights. For instance, a server with a weight of 3 will receive three times as many requests as a server with a weight of 1 within a given cycle.

  • Predictability: WRR offers deterministic request distribution and is O(1) per request, making it suitable for high-throughput environments.
  • Graceful Scaling: New, more powerful servers can be added with higher weights, automatically attracting more traffic without complex reconfigurations.
  • Simplicity: The algorithm is straightforward to implement and maintain, avoiding the overhead of more complex state-tracking methods.
go
type weightedLB struct {
  servers       []string
  weights       []int // same length as servers
  currentWeight int   // tracks how many more requests we can give to the current server
  currentIndex  int   // points to the server we are serving from
  totalWeight   int   // sum of all weights (used for reset)
}

func (lb *weightedLB) Next() string {
  for {
    lb.currentIndex = (lb.currentIndex + 1) % len(lb.servers)
    if lb.currentIndex == 0 { // new round
      // Logic to re-initialize current weights for a new round (simplified here for brevity)
    }
    // Simplified: in a real impl, you'd iterate through servers, decrementing weight
    // and move to next when weight hits 0, resetting currentWeight from weights slice
    // when a server's turn comes again.
    // The article's provided Go code offers a more robust in-place implementation.
    if lb.weights[lb.currentIndex] > 0 { // Check if server has weight (is healthy)
      // In a real WRR, you'd decrement current weight for this server before returning it
      return lb.servers[lb.currentIndex]
    }
  }
}
💡

Integrating Health Checks

To handle dynamic server conditions, WRR should be combined with robust health checks. If a server becomes unhealthy or degraded, its weight can be dynamically set to zero, effectively removing it from the rotation until it recovers. This prevents the load balancer from sending requests to failing nodes and improves overall system resilience.

Key considerations for implementing WRR include atomically updating weights when server health changes, guarding against scenarios where all servers have zero weight to avoid infinite loops, and re-initializing the load balancer state when the server pool itself changes (e.g., adding or removing nodes). Properly implemented, WRR significantly improves latency distribution and reduces error rates during peak loads, making it a versatile pattern applicable to various system components like HTTP proxies, database clients, or RPC gateways.

load balancingweighted round robinscalabilitydistributed systemstraffic managementhealth checkssystem architecture

Comments

Loading comments...