Rate limiter
Not climbed yetModel answer
Fixed window: one counter per user per minute (
rate:user42:10:31). Increment on each request; reject above 100; the key expires after the minute. Cheap and simple.Sliding window log: store the timestamp of every request and count those in the last 60 seconds. Exact, but stores up to 100 entries per user.
Sliding window counter: keep this minute's and last minute's counts and weight them by how far into the minute you are. Nearly exact with two numbers.
Return
429 Too Many RequestswithRetry-Afterand headers showing the remaining quota, so well-behaved clients can slow down.Model answer
A counter in each server's memory would let the user make 100 requests per server, 2,000 in all. The count must be shared: use Redis.
Make the check atomic: increment and set the expiry together, in a Lua script or a
MULTIblock, so two servers cannot both read 99 and both allow.local n = redis.call('INCR', KEYS[1]) if n == 1 then redis.call('EXPIRE', KEYS[1], 60) end return nThat adds a Redis round trip (around a millisecond) to each request. For very high traffic, servers can count locally and sync to Redis every few hundred milliseconds, accepting slight overshoot.
Model answer
The boundary resets the count, so a fixed window allows up to twice the limit around it. A sliding window fixes it by always looking at the last 60 seconds.
A token bucket gives each user a bucket of up to N tokens, refilled at a steady rate (100 a minute is one every 0.6 seconds). Each request takes a token; an empty bucket means 429. The bucket size sets how big a burst is allowed, the refill rate sets the average. Store just two values per user: tokens left and last refill time, updated in one Lua script.
A leaky bucket is the cousin that smooths output to a steady rate by queueing, useful in front of a fragile downstream service.
Model answer
It depends on what the limit protects, and you should decide in advance, not in the incident.
Fail open (allow) for ordinary API limits: a Redis blip should not take your whole product down, and a few minutes without limits is usually survivable.
Fail closed (block) where the limit stops abuse or cost: login attempts, OTP sends, expensive AI calls. Letting those through unlimited is how you get a large bill or a credential-stuffing attack.
A middle path: fall back to a local in-memory limiter on each server with a stricter per-server limit, and alert loudly. Keep the Redis call's timeout short so a slow Redis does not slow every request.
