Beginner8 min readlive prototype

Round Robin

Deal requests out like cards — server 1, 2, 3, 4, repeat. Perfectly even counts, blind to everything else.

Overview

What this concept solves

Round robin is the 'hello world' of load balancing: hand request 1 to server 1, request 2 to server 2, and so on, wrapping back to the start after the last server. It is the default in NGINX, the simplest mode in HAProxy, and the mental model most people reach for first — because it is genuinely good when its one assumption holds.

That assumption: every server is equally capable and every request costs roughly the same. When that's true, dealing requests out like cards produces a perfectly even split with essentially zero machinery — one integer counter, incremented modulo the number of servers.

Mechanics

How it works

One counter, modulo N

The entire algorithm is a pointer that walks the server list and wraps around:

  1. Keep an index next, starting at 0.
  2. On each request, forward it to servers[next].
  3. Advance: next = (next + 1) % N.

After N requests every server has received exactly one; after kN requests, exactly k each. The distribution is as even as it can possibly be, and the decision is O(1) with no knowledge of server state at all.

Why it's stateless (mostly)

Round robin looks at neither the servers nor the request — only its own counter. That makes it trivially fast and easy to reason about. The catch is that single shared counter: if many load-balancer instances each keep their own, their cycles drift out of phase and the global distribution is no longer a clean rotation (though it stays roughly even). True global round robin needs a shared, atomically-incremented counter, which reintroduces coordination cost.

The hidden assumption bites hard

Round robin is blind to how long a request takes. If request durations vary — one is a 2-second report, the next is a 5ms health check — round robin will happily stack three slow requests on server 2 while server 3 breezes through twenty fast ones. Even counts do not mean even load.

Interactive prototype

Run it. Break it. Tune it.

Sandboxed simulation embedded right in the page. No setup, no install.

About this simulation

Four identical servers behind one load balancer. Each request is sent to the next server in turn — 1, 2, 3, 4, 1, 2… Send requests one at a time or hit Start auto and watch the 'Next' pointer cycle and the handled counts stay dead even.

Hands-on

Try these on your own

Open the prototype above, run each experiment, predict the answer, then verify.

try 01

Watch the cycle

Click 'Send one' five times and follow the 'Next' label on the load balancer. It walks Server 1 → 2 → 3 → 4 → 1, and the handled counts climb in lockstep. After any multiple of four sends, all four counts are identical — that's the perfect even split round robin guarantees.

try 02

Let it run

Hit 'Start auto' and let it stream. The Distribution stat (S1 · S2 · S3 · S4) stays within one of being perfectly equal at all times. No server ever pulls ahead — that steadiness is round robin's whole selling point.

try 03

Imagine uneven durations

The sim gives every request the same flight time, so counts and load are the same thing here. Now picture request 2 taking ten times as long as the others: round robin would still deal server 2 its turn every fourth request, piling slow work on it regardless. Keep that gap in mind — it's exactly the blind spot Least Connections is built to close.

In practice

When to use it — and what you give up

When to reach for it

  • Homogeneous fleets — every backend is the same instance type with the same resources.
  • Uniform, short requests — stateless HTTP endpoints where every call costs about the same and finishes quickly.
  • You want predictability — round robin's behavior is completely deterministic and easy to explain in a postmortem.
  • A sane default — when you have no load metrics yet, round robin is the right place to start before measuring whether you need something smarter.

Real-world default

NGINX uses round robin as its default upstream method, and it backs countless production deployments. Most teams never need anything else — until request durations start varying, at which point least-connections earns its keep.

Pros

  • Dead simple: one counter, O(1) per request, trivial to implement and debug.
  • Perfectly even request counts across servers over each full cycle.
  • Completely stateless about backends — no health probing or connection tracking required.
  • Deterministic and predictable, which makes capacity planning easy.

Cons

  • Blind to request cost — even counts can mean wildly uneven load when durations differ.
  • Blind to server capacity — sends a small box and a big box the same share (that's what Weighted Round Robin fixes).
  • Blind to health — a slow or degraded server still gets its full 1/N until a separate health check ejects it.
  • Global ordering needs a shared counter; per-instance counters drift out of phase across distributed LBs.

Reference

Code & further reading

A minimal reference implementation and pointers worth bookmarking.

round-robin.ts
// Round robin: a single index that walks the pool and wraps.
class RoundRobinBalancer {
  private next = 0;
  constructor(private servers: string[]) {}

  pick(): string {
    const server = this.servers[this.next];
    this.next = (this.next + 1) % this.servers.length;
    return server;
  }
}

// Usage
const lb = new RoundRobinBalancer(["s1", "s2", "s3", "s4"]);
lb.pick(); // "s1"
lb.pick(); // "s2"
lb.pick(); // "s3"
lb.pick(); // "s4"
lb.pick(); // "s1"  (wraps around)

// Note: for global ordering across multiple LB instances,
// 'next' must be a shared, atomically-incremented counter
// (e.g. Redis INCR) — otherwise each instance cycles on its own.

References & further reading

6 sources

Knowledge check

Did the prototype land?

Quick questions, answers revealed on submit. No scoring saved.

question 01 / 03

What information does a round robin balancer use to choose a server?

question 02 / 03

Round robin distributes request counts evenly. Why can the actual load still end up uneven?

question 03 / 03

You run round robin across three load-balancer instances, each with its own counter. What happens to the global distribution?

0/3 answered

Was this concept helpful?

Tell us what worked, or what to improve. We read every note.