Rate Limiting, Quotas & Abuse Protection · Rate Limiting Fundamentals
Fixed Window, Sliding Log and Sliding Window Counter
Counting algorithms and their accuracy/cost trade-offs.
Fixed window: count requests per calendar window (e.g., per minute) — simple and cheap, but allows up to 2× the limit around window boundaries. Sliding log: store each request timestamp and count those in the last N seconds — exact but memory-heavy. Sliding window counter: weight the previous window's count by overlap (current + previous × (1 − elapsed/window)) — a good approximation with two counters, used by Cloudflare and many gateways.
Window algorithms
| Criterion | Fixed window | Sliding log | Sliding window counter |
|---|---|---|---|
| Accuracy | Boundary bursts up to 2× | Exact | Approximate (very close) |
| Memory per key | 1 counter | 1 entry per request | 2 counters |
| Redis commands | INCR + EXPIRE | ZADD/ZREMRANGEBYSCORE/ZCARD | 2× GET/INCR |
| Burst handling | Poor at edges | Smooth | Smooth |
| Use when | Low-stakes, simple | Small limits needing precision | General-purpose default |
import time
def allowed(redis, key: str, limit: int, window: int = 60) -> bool:
now = time.time()
current = int(now // window)
elapsed = (now % window) / window
cur_key, prev_key = f"{key}:{current}", f"{key}:{current - 1}"
cur, prev = redis.mget(cur_key, prev_key)
estimate = int(cur or 0) + int(prev or 0) * (1 - elapsed)
if estimate >= limit:
return False
pipe = redis.pipeline()
pipe.incr(cur_key).expire(cur_key, window * 2).execute()
return True
export async function allowedSlidingLog(key: string, limit: number, windowMs: number) {
const now = Date.now();
const res = await redis.multi()
.zRemRangeByScore(key, 0, now - windowMs)
.zAdd(key, { score: now, value: `${now}-${Math.random()}` })
.zCard(key)
.pExpire(key, windowMs)
.exec();
return Number(res[2]) <= limit;
}
Common pitfalls
- Fixed windows for login protection (attackers exploit boundaries).
- Sliding logs for high limits (memory explodes).
- Non-atomic read-modify-write races (use Lua/transactions).
Key points
- Fixed: cheap, bursty edges
- Sliding log: exact, expensive
- Sliding counter: practical default
Further reading: Cloudflare: Counting things
Practice questions
How can a fixed-window limit of 100/min allow 200 requests in a short time?
Answer
A client can send 100 requests at the end of one window and 100 at the start of the next, all within a few seconds.
How does the sliding window counter approximate a true sliding window?
Answer
It adds the current window's count to the previous window's count weighted by how much of the previous window still overlaps the sliding interval.
Open in the app to mark lessons complete, take notes and track your progress.