SysDesignPrep.com
Interactive concepts

Load balancing algorithms: an interactive comparison

A load balancing algorithm decides which server gets each request. Round robin and random spread requests evenly without looking at the servers. Least connections sends each request to the server with the fewest in progress, and power of two choices picks two servers at random and takes the less busy one. When servers and requests are all alike, any of them works; when one server is slow or some requests are long, only the ones that look at load keep response times down.

The playground routes the same minute of traffic to four servers with each algorithm. Start with one slow server, the case where they differ most, and watch its queue.

0 of 60 s, replayed 6× faster

One slow server, 80% load: Least connections has the best p99 (1.2 s), Random the worst (51 s). Round robin and random keep sending the slow server a quarter of the requests, more than it can finish, so its queue grows for the whole minute. Least connections and power of two choices see it is busy and send it only what it can handle.

Round robineach server in turn
0S1
0S2
0S3
0S4 slow
p50202 msp9948 smax queue186
Randomany server, at random
0S1
0S2
0S3
0S4 slow
p50308 msp9951 smax queue188
Least connectionsthe server with the fewest in progress
0S1
0S2
0S3
0S4 slow
p50132 msp991.2 smax queue6
Power of two choicesthe less busy of two random servers
0S1
0S2
0S3
0S4 slow
p50181 msp991.6 smax queue8

Bars are each server’s queue: requests waiting or being served. Every algorithm gets the same requests at the same moments.

How the load balancing algorithms work

  • Round robin: send each request to the next server in the list, then start again. Weighted round robin repeats bigger servers more often.
  • Random: pick any server. Even on average, but bunches up by chance.
  • Least connections (or least outstanding requests): send to the server with the fewest requests in progress, which is slow or busy servers’ way of saying “not me”.
  • Power of two choices: pick two servers at random and send to the one with fewer in progress.
  • Hashing (IP hash, consistent hashing on a key): always send the same client or key to the same server, for sticky sessions or cache locality, whatever the load.

Round robin vs least connections

Round robin assumes every server is as fast as every other and every request takes as long as every other. When that is true it is perfect and costs nothing. When it is not, it keeps sending a fair share to a server that cannot keep up: in the playground’s slow-server case at 80% load, round robin’s p99 climbs to about 48 seconds because one server’s queue never stops growing, while least connections stays near a second by sending that server only about an eighth of the requests. Counting requests in progress is the cheapest signal of how loaded a server is, and it reacts to slow servers, long requests and garbage collection pauses without being told.

Why power of two choices works

Choosing between just two random servers instead of one makes a dramatic difference: with one random choice the busiest of n servers ends up with about log n / log log n more than average, and with two choices about log log n, an exponential improvement. It also fixes least connections’ weakness at scale: with many load balancer instances each seeing slightly stale counts, they all pick the same least-loaded server at once and overload it, while random pairs spread out. That is why large fleets use it.

Which to use

AlgorithmSlow or busy serversUneven requestsNeedsSeen in
Round robinKeeps sending its shareQueues behind long onesNothingNGINX’s default
RandomKeeps sending its shareQueues behind long onesNothingSimple client-side balancing
Least connectionsRoutes around themRoutes around themCounts of requests in progressNGINX least_conn, HAProxy leastconn
Power of two choicesRoutes around themRoutes around themCounts for two serversEnvoy’s least request, NGINX random two least_conn
HashingKeeps sending its keysKeeps sending its keysA key per requestNGINX ip_hash and hash, cache tiers

A sensible default for HTTP services is least connections behind one balancer, or power of two choices when many balancers or clients choose independently. Keep round robin for identical servers with short, similar requests, and hashing for when the same key must reach the same server.

The algorithms in code

import random

def pick_server(servers):
    # power of two choices: two servers at random, the one with fewer requests in progress
    a, b = random.sample(servers, 2)
    return a if a.in_flight <= b.in_flight else b

def least_connections(servers):
    return min(servers, key=lambda s: s.in_flight)

def round_robin(servers, counter=[0]):
    counter[0] += 1
    return servers[counter[0] % len(servers)]

Whatever the algorithm, pair it with health checks that take a failing server out of the list, and connection draining so a server being deployed finishes its requests before it leaves.

In a system design interview

Name it in a sentence: “An L7 load balancer in front of stateless API servers, least outstanding requests, health checks every few seconds and connection draining on deploys; between services, client-side power of two choices.” Expect the follow-ups: sticky sessions (avoid them by keeping servers stateless), L4 vs L7 (L7 sees requests, so it can route by path and count requests rather than connections), what happens when a server is slow but healthy (outlier detection), and balancing across regions (DNS or anycast in front).

Read the load balancing guide and the tail latency guide, or watch a strong candidate design LLM inference serving, where routing by load matters most.

Questions people ask

What are the main load balancing algorithms?

Round robin sends each request to the next server in turn; random picks any server; least connections picks the server with the fewest requests in progress; power of two choices picks two random servers and takes the less busy one; and hashing sends the same client or key to the same server. Weighted versions give bigger servers more.

What is the difference between round robin and least connections?

Round robin gives every server the same number of requests whatever state it is in, so a slow server or a few long requests build up a queue. Least connections sends each request to the server with the fewest in progress, which steers traffic away from any server that is slow, busy or stuck on long requests.

What is the power of two choices in load balancing?

Pick two servers at random and send the request to the one with fewer requests in progress. It cuts the busiest server’s excess load from about log n / log log n to log log n compared with one random choice, and avoids the herd effect where many load balancers all pick the same least-loaded server at once.

Which load balancing algorithm is best?

For most HTTP services, least connections (least outstanding requests) behind a single balancer, or power of two choices when many balancers or clients choose independently. Round robin is fine when servers are identical and requests short and similar; hashing is for when a key must always reach the same server.

What is weighted round robin?

Round robin that sends each server a share proportional to its weight, so a server with twice the capacity gets twice the requests. It handles servers of known, fixed sizes, but not a server that becomes slow at runtime, which needs a load-aware algorithm such as least connections.

What is IP hash or sticky session load balancing?

A method that hashes the client’s IP address or a session cookie to choose the server, so the same client keeps reaching the same server. It suits servers that hold session state in memory, but it ignores load and moves sessions when servers are added or removed, so stateless servers are usually the better fix.

What is the difference between L4 and L7 load balancing?

An L4 load balancer routes TCP or UDP connections by address and port without reading them, so it is fast but can only balance connections. An L7 load balancer reads each HTTP request, so it can route by path or header, retry, and balance individual requests over long-lived connections.