Rate Limiting

Redis Rate Limiting

Implement API rate limiting with Redis to protect your services from abuse. Learn sliding window, token bucket, and fixed window patterns.

Real-World Business Scenario

A public API serves 10,000 developers. Without rate limiting, a single misbehaving client can exhaust server resources and degrade service for everyone. You need to enforce 100 requests per minute per API key, with clear feedback when limits are exceeded. Redis provides atomic counters and expiration to implement this efficiently at scale.

Architecture Diagram

API Request + API Key Header
API Gateway / Middleware
↓ Check Rate Limit
┌──────────────────────────────────┐
│ Redis (Rate Limit Counters) │
│ ┌────────────────────────────┐ │
│ │ ratelimit:{apiKey}:{window} │ │
│ │ Value: request count │ │
│ │ TTL: window duration │ │
│ └────────────────────────────┘ │
└──────────────────────────────────┘
↓ Under Limit → Forward
Backend Service

Key Commands Explained

Performance Analysis

INCR is O(1) — constant time regardless of request volume. Adds ~0.1ms overhead per request.
Fixed window: 1 key per user per window. 10K users × 1 key = 10K keys. Minimal memory footprint.
Sliding window (sorted set): O(log N) per operation. More accurate but slightly higher cost. Good for up to ~1000 requests per window.
Redis handles 100K+ INCR/sec on a single instance — sufficient for most rate limiting needs without clustering.

Common Pitfalls

Fixed Window Boundary Burst: A user can send 100 requests at minute :59 and 100 more at :00, effectively 200 in 2 seconds. Use sliding window or sliding log to prevent this.
Race Condition on INCR + EXPIRE: If EXPIRE fails after INCR, the key persists forever and the counter never resets. Always use MULTI/EXEC or Lua scripts.
Clock Skew in Distributed Systems: If app servers have different clocks, window boundaries differ. Use Redis server time (TIME command) as the source of truth.
Missing Rate Limit Headers: Always return X-RateLimit-Limit, X-RateLimit-Remaining, and Retry-After headers so clients can self-throttle.

Best Practices

Use Lua scripts for atomic check-and-increment to eliminate race conditions.
Implement multiple tiers: per-second burst limit + per-minute sustained limit.
Return HTTP 429 with Retry-After header when limit is exceeded.
Use sliding window for user-facing APIs where fairness matters.
Add rate limit info to response headers on every request, not just rejections.
Consider token bucket for APIs that need to allow short bursts above the average rate.

Runnable Demo

Redis Demo
Click "Step" or "Run All" to execute commands...

Try these commands in our online Redis editor