One limiter, one truth
A single replica with in-memory counters.
Exactly 10 allowed, 20 denied.
Replicas, shared counters and failure modes, live.
Each scenario sets up replicas, Redis and policy, resets counters, then sends traffic.
A single replica with in-memory counters.
Exactly 10 allowed, 20 denied.
Add a second replica, each still counting in its own memory.
About 20 allowed. Each replica happily allows its own 10.
Both replicas count atomically in Redis.
Back to exactly 10 allowed across both replicas.
Stop Redis while the limiters depend on it.
All 30 allowed, uncounted. The API stays up, unprotected.
Same outage, but the limiter refuses when it can't count.
All 30 rejected with 503. Protected, but fully down.
10 tokens, refilling at 1/s. Requests arrive every 250 ms for 10 s.
A burst of 10, then roughly every 4th request passes (~20 total).
Applied live to every running replica
One INCR per request. Allows up to 2× the limit across a boundary.
Limit10 requests per 60 s, per client.
Counter storeEvery replica increments one atomic counter in Redis, so the limit holds globally.
If Redis is unreachableLet requests through uncounted. The API stays up, unprotected.
Real containers, started and stopped through Docker
This switches the Redis container. Whether the limiters count in it is the Counter store setting.
Requests travel nginx → limiter → api, exactly like real clients
30 requests one at a time, as a single client.
Every ALLOW / DENY decision, straight from the containers