Make the right trade-off / CHAPTER 32
Token bucket versus leaky bucket
Control bursts and steady work deliberately, including atomic accounting and overload behavior.
Builds on Functional and non-functional requirements, Back-of-the-envelope estimation.
- Calculate token replenishment and burst allowance.
- Distinguish policing from queued shaping.
- Prevent two servers from spending the same token and define accounting-store failure behavior.
01A rate and a burst are different limits
A customer organization shares an API allowance across all its users and servers. We want to allow occasional bursts without letting it consume unlimited sustained work.
A token represents permission to do some work. A token bucket:
- Keeps up to
Btokens as saved credit. - Adds
rtokens per second, stopping atB. - Lets a request proceed only if it can spend the required tokens.
An ordinary read may cost one token and an expensive export five. Idle time earns credit up to the limit, so a short permitted burst can proceed immediately. A component making this immediate allow-or-reject decision is a policer.
“Leaky bucket” has two related meanings. A queued shaper holds requests and releases them at a controlled rate, adding waiting time. A meter instead estimates how much work an imaginary queue would still contain and immediately rejects work exceeding its limit. State which behavior you mean; the name alone does not tell callers whether they wait.
02Implement accounting as one decision
Give the organization 20-token capacity and refill at 5 tokens/s. All API servers must use the same allowance or reserved portions of it.
For each request, one indivisible operation does the following:
- Read the balance and last-refill time stored under the organization's key.
- Calculate earned credit: elapsed seconds × 5, then cap
oldBalance + earnedCreditat 20. - Compare the request's cost with that available balance.
- If enough credit exists, deduct the cost and allow the request. Otherwise reject it without deducting its cost. Save the newly refilled balance and time in that same indivisible operation, including on rejection.
“Atomic” means another caller cannot slip between the comparison and deduction. If two servers each read one token and later write separately, both can spend that last token. A shared transaction or script must protect the complete decision, not just each final write. Define clock source, precision and state expiry; recreating a full bucket too early can grant unearned credit.
| Mechanism | What is stored? | What happens to an excess request? |
|---|---|---|
| Token bucket | Available credit and refill time. | It is normally rejected immediately when credit is insufficient. |
| Queued leaky shaper | Requests waiting for controlled release. | It waits while space exists, then is rejected when the finite queue fills. |
| Leaky meter | An estimate of unfinished work that decreases with elapsed time. | It is immediately allowed or rejected against that estimate, without an actual request queue. |
03Worked example: a permitted burst
Start at time zero with 20 tokens and one token per read.
- Twenty simultaneous reads spend all 20. An immediate twenty-first read is rejected; merely receiving a request does not earn a token.
- Wait 0.4 seconds from empty. Five tokens/s × 0.4 seconds earns two tokens, enough for two reads. Two idle seconds earns ten.
- Charge an export five tokens. It consumes the same allowance as five ordinary reads, making the limit better reflect expensive work.
- Avoid independent full buckets on ten servers. They permit ten bursts and about 50/s aggregate refill. To enforce 5/s total, share the balance or reserve constrained portions from one total.
Now queue 20 requests in a shaper that releases one every 200 ms, equivalent to 5/s. If the first release is immediate, the twentieth leaves after 19 gaps: 3.8 seconds. That cannot fit a 200 ms interactive target unless most requests are rejected or the queue is much smaller. A different first-release convention changes the calculation, so state it.
Also protect unfinished work separately. At 10 admitted requests/s and 0.1 s mean duration, average in-flight work is one. At two seconds it becomes 20 under stable load. The arrival rate stayed allowed, but the requests now occupy many more worker slots or connections.
Token bucket versus leaky bucket — decision flow
Follow the numbered arrows
- Customer API requests → Shared token balancerefill, compare and spend atomically
- Shared token balance → Protected APIallow the request after deducting tokens
- Shared token balance → Reject excess workreject when credit is insufficient
Trace the diagram in words
- Look up the organization’s stored balance and last-refill time.
- In one indivisible operation, add earned credit, check the request cost and deduct it if allowed.
- Reject work without credit and provide retry guidance; do not promise an unlimited waiting queue.
04Match the rule to the protected resource
Match the control to the resource:
- Use a token bucket when a short burst is useful and the backend can absorb it.
- Use queued shaping when smoother output matters and callers can tolerate the calculated wait. Set a finite queue limit.
- Limit concurrency as needed. An arrival limit does not stop slow requests from occupying every connection.
- Limit total work as well as each organization. Many customers respecting their own limits can still overwhelm one database.
- Choose behavior when the allowance store fails. Fail-open accepts work without exact shared accounting; fail-closed rejects because remaining credit cannot be established. A strict spending cap cannot safely become unlimited during an outage.
- Reserve limited local credit if useful. Subtract each server's allocation from the shared total in advance; during failure it can spend only that amount.
- Guide rejected clients. Estimate when refill would cover the missing tokens and tell the client when to try again. This is not reserved credit: other requests may spend it first. Encourage longer waits after repeated rejection, with varied retry times so clients do not all return together.
State the accounting key, capacity, refill rate, cost, atomic update, maximum wait and outage behavior. These details determine what the algorithm actually permits.
DRAW. CALCULATE. EXPLAIN.
Walk a weighted burst
20 minutes · guided practice
Capacity is 30, refill 10/s. A tenant sends 24 one-token reads and two five-token exports simultaneously through four servers. Assume reads are processed first. After one idle second, another export arrives. Calculate admission and choose behavior when shared accounting fails.
Compare the worked solution
- Process the reads first against one shared balance. Twenty-four one-token reads leave 6 of the original 30 tokens.
- One five-token export fits and leaves 1. The second export is rejected.
- One idle second at 10 tokens/s raises the balance to 11. The next export fits and leaves 6.
- Four servers must not each create a new 30-token balance. Use one atomic balance update or portions reserved from the shared total.
- For a strict spend cap during an outage, reject unknown-credit requests or spend only preallocated local credit. State the finite total that can still be spent.
The checkboxes record your own assessment. The worked solution gives you a way to check the reasoning.
RETRIEVE BEFORE YOU REVEAL
Keep the important ideas.
Say the answer aloud, then turn the card over.
CARD 01How does a token bucket decide?
In one indivisible update:
- Refill earned tokens up to capacity.
- Compare the request cost.
- Deduct only if allowed.
Capacity permits bursts; refill rate controls sustained credit.
CARD 02How do leaky-bucket variants differ?
- A queued shaper holds requests and releases them at a controlled rate.
- A meter tracks an imaginary unfinished-work count and immediately allows or rejects.
State whether callers wait and how much work may accumulate.
CARD 03What can a rate limit miss?
- An allowed arrival rate can still fill every worker when requests slow down.
- Limit simultaneous work separately.
- State whether allowance covers one user, organization or the entire service.
CHECK THE REASONING
Can you explain the choice?
Answer every question, then finish for an immediate score and an explanation for each answer. Aim for 80%, then revisit any gaps.
CLOSE THE LOOP
Explain it without the page.
Summarise the mechanism, one trade-off, and one failure mode. Then mark this chapter complete.