Free preview

Leaking Bucket and Fixed Window Counter

In one line: leaking bucket is the one algorithm that cannot burst, which makes it right for a specific class of downstream. Fixed window is the simplest, and its boundary bug is the most commonly asked question in this chapter.

The leaking bucket algorithm

ParameterMeaning
Bucket capacity (C)The maximum queue size. Requests are discarded if the queue reaches capacity C
Inflow rate (R_in)The rate at which requests arrive
Outflow rate (R_out)The constant rate at which requests are processed
Detail
AdvantagesThe constant outflow rate prevents traffic bursts · memory efficient, requiring only three states (inflow rate, outflow rate, capacity) · suitable for applications requiring a stable outflow rate
DisadvantagesBursts can fill the bucket quickly, potentially delaying recent requests · determining the optimal bucket size and outflow rate is challenging

Token bucket and leaking bucket are near-mirror images

Both use a bucket metaphor, and that similarity hides an opposition worth stating cleanly.

Token bucket holds permits that accumulate while you are idle. A burst is served immediately if credit exists. Output rate is variable; input is unconstrained.

Leaking bucket holds requests that drain at a fixed speed. A burst is queued and paced out. Output rate is constant; input is buffered.

So the deciding question is: what does the downstream need? If it can absorb a spike, token bucket serves the burst and everyone is happier. If it cannot — a legacy system, a third-party API with hard limits, a device with a fixed processing rate — leaking bucket guarantees it never sees more than R_out, no matter what arrives.

Token bucket protects a rate budget; leaking bucket protects a downstream.

Why not always use leaking bucket if constant outflow is 'better'?

"If the leaking bucket ensures a constant outflow, why not always prefer it over the token bucket for predictable systems?"

Because constant outflow buys predictability by spending latency, and it spends it on the wrong requests.

A burst fills the queue. Every request behind that burst now waits — including a request from a completely different user who arrived while the queue was draining. "bursts can fill the bucket quickly, potentially delaying recent requests." Recent, well-behaved traffic pays for earlier bad behaviour.

There are two further costs. It holds state per queued request, not per client, so a deep queue is real memory. And queued requests may become worthless — a client that timed out five seconds ago still has its request sitting in the bucket, and you will dutifully process it, spending capacity on a response nobody will read.

Token bucket rejects immediately instead, which is often kinder: the client learns now and can retry with backoff, rather than waiting and then timing out.

So the answer is: prefer leaking bucket when the downstream genuinely cannot absorb bursts, and accept the latency. Otherwise the fast rejection is usually better behaviour.

The trade that distinguishes it from token bucket: token bucket rejects excess immediately, leaking bucket delays it. Rejection is honest and fast; queuing is gentler on the client and turns an overload into a latency problem, which is worse when the queue is unbounded.

The fixed window counter algorithm

Key takeaway

Divides time into fixed intervals (windows) and assigns a counter to each. When a request arrives, the counter for the current window increments. If the counter exceeds the limit, new requests are discarded until the next window begins.

ParameterMeaning
Window size (W)The duration of the time window (e.g. one minute)
Rate limit (R)The maximum number of requests allowed per window
Requests count (N)The number of incoming requests in the current window. Requests are allowed if N is less than or equal to R
Detail
AdvantagesMemory-efficient due to constraints on request rate · ensures new requests are processed as long as the window limit isn't reached
DisadvantagesTraffic bursts at window edges can temporarily exceed the rate limit

The boundary problem

A significant drawback is the potential for traffic bursts at window edges. The source's example:

Limit: 10 requests per minute

01:00 --------- window 1 --------- 02:00 --------- window 2 --------- 03:00
                              ^^^^         ^^^^
                          10 requests   10 requests
                          at 01:59      at 02:00

Window 1 count = 10   (within limit)
Window 2 count = 10   (within limit)

But the interval 01:59 -> 02:01 saw 20 requests
in roughly two seconds. Twice the intended rate.

Fixed window can serve exactly 2x its limit, and it is trivially exploitable

This is the most-asked follow-up in the whole chapter, so be able to state it crisply: a client can always achieve 2R in a window of size W by firing R requests at the very end of one window and R at the very start of the next.

It is not a rare race — it is deterministic and easy to exploit. Any client that knows your window boundaries (and boundaries are usually aligned to wall-clock minutes, so they are guessable) gets double the limit for free.

Compare with token bucket's edge case from Lesson 8: that overshoot was bounded by the bucket capacity, a parameter you chose deliberately to permit bursts. Fixed window's overshoot is not a design choice — it is an artifact of resetting the counter at an arbitrary instant.

The fix is what the remaining two algorithms do: stop treating time as discrete buckets and start measuring a window that moves with the request.

Fixed window is still the right answer sometimes

Do not over-learn the criticism. Fixed window is one integer per client per window — the cheapest possible state — and it is trivially implementable with INCR plus EXPIRE in Redis, which Lesson 6 showed is atomic and fast.

When the limit is a soft capacity guard rather than a strict contract, 2x overshoot in the worst-aligned instant is often irrelevant. If you are protecting a service that can handle 10x its nominal load, the boundary bug costs you nothing and you saved real complexity.

The rule: fixed window is fine when the limit is approximate and the state budget is tight. It is wrong when the limit is a billing quota, a security control, or anything a client has an incentive to game.

Key takeaway

Leaking bucket queues and drains at a constant rate — it never bursts, but it delays recent requests behind earlier ones and can process work clients have already abandoned. Use it when the downstream cannot absorb spikes. Fixed window counter is the cheapest algorithm and allows a deterministic 2x at window boundaries — fine for approximate capacity guards, wrong for anything enforceable.

This is the defect that motivates both sliding-window variants, and it is worth drawing rather than describing: the overshoot is not a tuning problem, it is structural to resetting a counter at a fixed instant.

Interview signal by level

LevelWhat a strong answer sounds like
L4"Leaking bucket queues requests; fixed window counts them per minute."
L5Names the boundary bug: "fixed window lets a client send the full limit at the end of one window and again at the start of the next — 2x the rate across the boundary."
Staff+Contrasts the buckets and qualifies the criticism: "token bucket stores permits and serves bursts immediately; leaking bucket stores requests and paces them, so it protects a downstream that genuinely can't absorb spikes — at the cost of delaying well-behaved recent traffic behind an earlier burst, and processing requests clients have already timed out on. And fixed window's 2x is deterministic and exploitable since boundaries align to wall-clock minutes — but it's one integer per client, so it's still right when the limit is an approximate capacity guard."

Next: the two algorithms that fix the boundary.

Enjoying the preview?

Create a free account to unlock the rest of this course, the in-browser judge, and live AI mock interviews.

Sign up free to continue