mdashikjs/blog
All posts
Load Balancing Algorithms: Round Robin, Least Connections, and Beyond
System Design

Load Balancing Algorithms: Round Robin, Least Connections, and Beyond

System Design5 min

Load Balancing Algorithms: Round Robin, Least Connections, and Beyond

Choosing a load balancing algorithm is choosing a trade-off. Round robin is simple but blind. Least connections is smarter but stateful. Here is when each one makes sense.

Load BalancingNginxSystem DesignInfrastructure
Share:

Round Robin

The simplest algorithm. Requests go to servers in order: A, B, C, A, B, C.

Request 1 → Server A
Request 2 → Server B
Request 3 → Server C
Request 4 → Server A

Works when all servers are identical and all requests cost roughly the same. Breaks down when one server is slower than the others or when some requests are expensive (file uploads, report generation).

Weighted Round Robin

Same as round robin, but servers with higher capacity get more requests:

upstream api {
  server 10.0.1.1 weight=5;  # 2x CPU
  server 10.0.1.2 weight=3;  # 1.5x CPU
  server 10.0.1.3 weight=2;  # baseline
}

Useful when your fleet is heterogeneous — some instances have more CPU or memory than others.

Least Connections

Routes each request to the server with the fewest active connections. This naturally adapts to slow servers: a server that is processing a slow request accumulates fewer new requests.

upstream api {
  least_conn;
  server 10.0.1.1;
  server 10.0.1.2;
  server 10.0.1.3;
}

This is my default choice for most API backends. It handles variable request costs better than round robin with no extra configuration.

IP Hash

Routes requests from the same client IP to the same server. Useful for sticky sessions when your app stores session state in memory:

upstream api {
  ip_hash;
  server 10.0.1.1;
  server 10.0.1.2;
}

The downside: if one server goes down, all clients pinned to it get redistributed. If your sessions are in Redis or a database, you do not need IP hash — use least connections instead.

Random with Two Choices

Pick two servers at random, send the request to the one with fewer connections. This sounds crude but it is surprisingly effective. The "power of two choices" is a well-studied phenomenon — it avoids the herd behavior that plagues pure least-connections in large clusters.

Nginx does not support this natively, but Envoy and HAProxy do.

Health checks matter more than the algorithm

The best algorithm in the world is useless if it routes traffic to dead servers. Active health checks probe each server periodically:

upstream api {
  least_conn;
  server 10.0.1.1 max_fails=3 fail_timeout=30s;
  server 10.0.1.2 max_fails=3 fail_timeout=30s;
  server 10.0.1.3 max_fails=3 fail_timeout=30s;
}

After 3 failures in 30 seconds, Nginx marks the server as down and stops routing to it. After 30 seconds, it tries again.

Layer 4 vs Layer 7

  • Layer 4 (TCP): routes based on IP and port. Faster, lower overhead. Cannot inspect HTTP headers or paths.
  • Layer 7 (HTTP): routes based on URL paths, headers, cookies. More flexible. Slightly higher latency.

For most web apps, Layer 7 is the right choice because you need path-based routing (/api to backend, / to frontend). For high-throughput internal services, Layer 4 reduces overhead.

My recommendation

Start with least connections behind Nginx or an AWS ALB. It handles 95 percent of use cases. Only reach for something more complex when you have evidence that the simple approach is not working.

MA

Written by Md Ashik

Senior Software Engineer building reliable backends. I write about the practical tradeoffs behind shipping software that holds up in production.