Why you shouldn’t use Redis as a rate limiter: Part 1 of 2
A tour of the common Redis-based rate limiter implementations — and the correctness and performance traps each one hides.
We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
Rate limiting and admission checks that help reduce overload and protect expensive work.
Set admission budgets for launch spikes and promos before excess work reaches your handlers.
Fewer moving parts to run and monitor. Spend less on Redis and ops.
Add via SDK. Keep your stack. Clear limits your customers understand.
UNDERSTAND OVERLOAD · KEEP USEFUL WORK MOVING
For developers, architects, and managers: 27 narrated lessons on why services overload and how to protect them. No cloud experience required. Start with one request, or jump to any lesson.
Four chapters, one learning path. Read or listen in any order. ~41 minutes total · Times shown at 1×.
Keep enough capacity to finish work and recover.
Contain one customer's excess without punishing everyone.
Reduce work entering a shared dependency when it slows.
Choose, combine, and test the right protections.
Read the explanation or use the course map above. Audio is optional.
Replica capacity and redistribution
Each can serve a request.
Work does not have to pass through all three.
Illustrative equal-cost rates and even routing. Server positions stay fixed. Active arrows carry work; STOPPED supplies no capacity. Desktop gauges all use the same 0–240/s scale.
Read the numbered steps in order. The explanation below follows the narration.
A load balancer distributes work across application replicas.
240 requests/s ÷ 3 = 80 each; after one loss, 240 ÷ 2 = 120 each.
240 requests/s ÷ 3 = 80 each; after one loss, 240 ÷ 2 = 120 each.
A service can run several copies of its application. Each copy is a replica. Here they are servers A, B, and C. A load balancer distributes requests between copies that can serve them. In our example, each can finish one hundred equal-cost requests per second.
With two hundred forty requests per second, divided evenly, each receives eighty. Now server A stops. Once the balancer detects that failure, it redirects those requests. Each survivor now receives one hundred twenty per second, but can still finish only one hundred. Demand did not increase. Available capacity decreased.
If the survivors retain all that work, each accumulates twenty extra unfinished requests every second. Waiting and memory can grow. If server B also stops, server C receives all two hundred forty requests per second. It cannot finish one hundred forty of those each second. If C then fails, no serving copies remain. This spread through the effects of an earlier failure is a cascading failure.
Is that chain inevitable? No. Enough spare capacity, or refusing excess work, can interrupt it. For example, with two survivors, admitting ninety requests per second to each and refusing sixty overall leaves room below their combined capacity. Those numbers illustrate the principle, not a safe production setting. Refusal itself costs resources. Test that remaining capacity can finish accepted work and respond when a replica disappears.
A, B, and C are individual serving copies, not three stages in one request. Keeping their names and positions fixed lets us follow what happens to each one as capacity is lost.
The branching arrows are alternative destinations for incoming requests. They do not mean that one request is copied to all three servers, and the load balancer does not increase each server’s processing speed.
In this worked example, each copy can finish 100 equal-cost requests per second. We have not assigned demand yet. Three healthy copies supply 300/s of combined capacity under these assumptions.
The same 240 requests per second are distributed evenly: A, B, and C each receive 80. Each is below its 100/s finishing capacity. The gauge scale stays fixed across every later step.
A has stopped. B and C are still in the same positions. This intermediate picture separates the lost path from the following redistribution: 80/s previously directed to A must now be handled or fail.
After detection, this example routes all 240/s to B and C. Real detection and routing can take time; the diagram is a causal sequence, not a timing benchmark or a guarantee of even balancing.
Both surviving servers cross the 100/s capacity marker. Demand has not increased; total usable capacity fell from 300/s to 200/s. More traffic reaches each remaining copy because there are fewer copies.
If each server keeps everything it cannot finish, 120 arriving minus 100 finishing leaves 20 extra unfinished requests every second on each. Their waiting work can retain memory; growth is conditional on that work not being bounded or removed.
Follow the severe branch: B also stops and the whole demand is routed to C. C’s capacity has not grown: 240 arriving minus 100 finishing leaves 140/s of excess if it accepts and retains everything.
In this explicitly conditional severe outcome, the last application copy also fails. Incoming customer demand still exists, but there is no serving application capacity; failure has spread through the earlier losses.
This is an alternative to the severe continuation, not an automatic restart. A is unavailable, while B and C still have a chance to survive if enough capacity remains or excess work is refused.
An illustrative alternative admits 90/s to each survivor: 180/s accepted and 60/s refused out of the same 240/s offered. Both stay below the assumed 100/s finishing capacity; this is not a recommended production threshold.
The refused requests still consume some network, routing, and response resources. Test the real request mix and loss behavior: the numerical margin here explains the idea but cannot prove a safe threshold for your deployment.
Content revision: 07c7dd00db17
Download review copy (27 lessons)Why can one failed replica put healthy survivors at risk?
Demand is redistributed onto fewer replicas. Each survivor can exceed its own capacity.
Test replica loss at expected demand, including detection delay, redistribution, retained work, and the cost of refusing excess on survivors.
The example assumes even redistribution and no additional capacity. A failed replica need not cause a fleet outage.
Start here. No earlier lesson is required.
Accepting a request is not the same as delivering a useful result.
100 arrivals/s − 80 completions/s = 20 extra unfinished requests/s.
Waiting work can retain memory. A failed allocation or terminated process can stop service.
Aggregate healthy capacity is not necessarily evenly usable. Include uneven routing, expensive request mixes, and resources consumed by refusals. The 90/s admitted example is not a recommended production threshold.
Original explanation inspired by Fred Hébert and operational references; no endorsement implied.
AI-generated narration: ElevenLabs Eleven v3, Daniel stock voice. Audio streams only when you start listening.
A tour of the common Redis-based rate limiter implementations — and the correctness and performance traps each one hides.
The myth of infinite serverless scale — why adding machines doesn’t fix overload, and what to do instead.