At staff level you're not graded on the diagram. You're graded on the reasoning that survives scrutiny. Tonight: the loop that makes a correct answer read as a senior one, run end-to-end on a real system.
An interview answer that works. An RFC that's sound. Both stall, because being right is invisible until you make the reasoning legible. The boxes were never the bottleneck.
Two engineers draw the identical architecture. One is rated staff, the other "needs seasoning." Same boxes. What surrounded them, the constraints, the quantified tradeoff, the failure story, the evolution path, was not the same.
The spine you narrate out loud so a reviewer can follow, and grade, your thinking in real time.
INCR a key per user with a TTL. Over the limit, reject."↑ correct. and a 4/10. watch the same idea become staff-level.
| Given | 50k rps peak · 2M users · cap 100 req/min/user · p99 budget < 5 ms |
| Non-goal | global exactness across regions — approximate is fine, say so up front |
| State | 2M × ~30 B/bucket ≈ 60 MB → fits one Redis node's RAM, trivially |
| Ops | 50k rps × 1 atomic op = 50k ops/s → under one primary (~100k+ ops/s) |
| Hop | +1 round trip intra-AZ ≈ 0.2 ms → inside the 5 ms budget |
| Verdict | centralized Redis works to ~100k rps; the ceilings are primary ops/s and the per-call hop |
Why Lua: check-refill-decrement must be one round trip, or two concurrent requests both read N and both pass. Atomicity on the node closes the race, and refill uses the node's clock, so no client skew.
-- KEYS[1]=tokens KEYS[2]=ts ARGV: now, capacity, refill_per_ms
local tokens = tonumber(redis.call('GET', KEYS[1]) or ARGV[2])
local last = tonumber(redis.call('GET', KEYS[2]) or ARGV[1])
tokens = math.min(ARGV[2], tokens + (ARGV[1] - last) * ARGV[3]) -- lazy refill
if tokens < 1 then return 0 end -- reject, no write
redis.call('SET', KEYS[1], tokens - 1)
redis.call('SET', KEYS[2], ARGV[1])
return 1 -- allow
| Algorithm | Accuracy | Memory / key | Boundary burst | Cost |
|---|---|---|---|---|
| Fixed window | low | O(1) | up to 2× | trivial |
| Sliding window log | exact | O(req) | none | heavy |
| Sliding window counter | good | O(1) | minor | moderate |
| Token bucket | good | O(1) | smooth, tunable | atomic refill |
Replica + Sentinel for failover. The limiter must never be the reason the API is down.
Fall back to a local in-process bucket. Bounded over-admission beats a global outage on a soft control. Per-route flag.
5 ms timeout + circuit breaker on the Redis call. Limiter degrades; requests still flow.
One abusive key won't shard; pre-check locally and approximate at the extreme. Refill clock is the node's, not callers'.
Each hop trades a little exactness for locality, deliberately. That sentence is the difference between "I'd scale it" and showing you know what scaling costs.
Six weeks of live design under stakeholder pushback, with direct feedback on how you defend, not just what you draw. Small cohort, so the feedback is personal.