Rate limiting: what token bucket and leaky bucket really differ on

A token bucket permits bursts; a leaky bucket flattens traffic to a constant rate. Picking wrong shows up as throttled normal users, or a limit that does nothing.

The two classic rate limiting models get treated as synonyms, but their output shape is completely different: one preserves bursts, the other erases them.

Token bucket: bursts allowed

Tokens accumulate at a fixed rate into a bucket of capacity C. A request takes one token, and takes nothing if the bucket is empty.

  • Rate R sets the long-run average throughput
  • Capacity C sets how large a burst survives

After an idle period the bucket is full, so C requests pass instantly. That is required for normal behavior such as a page firing 20 requests at once. A leaky bucket spreads them out and the user watches things load one at a time.

Leaky bucket: constant output

Requests enter a queue and leave at a fixed rate. A full queue drops.

Output is constant, and the cost is added latency: requests wait in the queue. Stronger protection for the downstream, worse experience for the caller.

Comparison

Dimension Token bucket Leaky bucket
Output rate variable, up to C constant
Bursts allowed not allowed
Adds latency no yes
Protects services with headroom fragile downstreams

Choosing

Ask one question: can the downstream absorb a burst?

Scenario Pick Why
Public API gateway token bucket real usage is bursty
Paid third-party API leaky bucket the vendor bills per second
Database connection pool leaky bucket a burst exhausts connections
Per-user frequency cap token bucket short dense activity is fine

The distributed trap

Counting in process memory across several instances multiplies your limit by the instance count. Either share state (Redis INCR with expiry) or allocate limit / instanceCount to each.

Watch atomicity with Redis: a GET then SET races. Use INCR with EXPIRE, or one Lua script that does both.

Which status code

Return 429 Too Many Requests with a Retry-After telling the client how long to wait. A 429 without Retry-After makes clients retry blindly, which amplifies your own traffic.

A token bucket manages long-run average plus a burst budget; a leaky bucket manages constant output. Decide what your downstream can absorb first.

← Back to all posts

Comments

…