| Users | Requests per Second (RPS) | Storage Needs | Latency Impact | System Changes |
|---|---|---|---|---|
| 100 users | ~1,000 RPS | Minimal (in-memory counters) | Low latency | Single server with in-memory rate limiting |
| 10,000 users | ~100,000 RPS | Moderate (distributed cache) | Low to moderate latency | Distributed cache (e.g., Redis cluster), load balancer |
| 1,000,000 users | ~10,000,000 RPS | High (sharded cache and DB) | Moderate latency | Sharded caches, multiple rate limiter instances, consistent hashing |
| 100,000,000 users | ~1,000,000,000 RPS | Very high (multi-region, sharded storage) | Higher latency possible | Global distributed rate limiting, hierarchical limits, CDN edge enforcement |
Design a rate limiter in HLD - Scalability & System Analysis
Start learning this pattern below
Jump into concepts and practice - no test required
The first bottleneck is the storage and update of counters that track user requests. At low scale, in-memory counters on a single server work well. As users and requests grow, the rate limiter's data store (like Redis or database) becomes the bottleneck because it must handle many read/write operations per second with low latency.
- Horizontal scaling: Add more rate limiter instances behind a load balancer to distribute traffic.
- Distributed caching: Use Redis clusters or similar to store counters with fast access.
- Sharding: Partition counters by user ID or API key to spread load across multiple nodes.
- Token bucket or leaky bucket algorithms: Use efficient algorithms to reduce storage and computation.
- Local caching with periodic sync: Cache counters locally and sync with central store to reduce writes.
- CDN edge enforcement: For global scale, enforce limits closer to users to reduce central load.
- At 10,000 users with 10 RPS each = 100,000 RPS total.
- Each request requires 1 read + 1 write to counter -> 200,000 ops/sec on data store.
- Redis single instance handles ~100,000 ops/sec -> need 2+ Redis nodes or cluster.
- Storage: counters are small (few bytes each), but millions of users require efficient memory use.
- Network bandwidth: assuming 1 KB per request metadata, 100,000 RPS = ~100 MB/s bandwidth.
Start by explaining the rate limiter's purpose and basic algorithm (fixed window, sliding window, token bucket). Then discuss expected traffic and identify bottlenecks. Propose scaling solutions step-by-step, focusing on data store limits and latency. Mention trade-offs like accuracy vs. performance. Finally, consider global scale and edge enforcement.
Your database handles 1000 QPS. Traffic grows 10x to 10,000 QPS. What do you do first?
Answer: Add read replicas and implement caching to reduce database load. Also, consider sharding counters or moving counters to a faster in-memory store like Redis to handle increased QPS.
Practice
Solution
Step 1: Understand the role of rate limiter
A rate limiter restricts how many requests a user or client can send in a certain time to prevent overload.Step 2: Identify the correct purpose
Among the options, only controlling request rate matches the rate limiter's function.Final Answer:
To control the number of requests a user can make in a given time -> Option AQuick Check:
Rate limiter = control request rate [OK]
- Confusing rate limiter with load balancer
- Thinking it speeds up database queries
- Assuming it stores user data
Solution
Step 1: Recall sliding window mechanism
Sliding window rate limiter tracks timestamps of requests in a time window, removing old ones as time moves.Step 2: Choose data structure for efficient insert and remove
A queue allows adding new timestamps at the end and removing old timestamps from the front efficiently, matching sliding window needs.Final Answer:
Queue -> Option CQuick Check:
Sliding window = queue for timestamps [OK]
- Using stack which is LIFO, not suitable
- Choosing hash map without order
- Picking binary tree which is complex here
Solution
Step 1: Track requests in 10-second window
Requests at 1, 3, 7 are allowed as they are within limit 3 per 10 seconds.Step 2: Check request at second 9
At second 9, previous requests at 1, 3, 7 are still within 10 seconds window (from -1 to 9). So 3 requests already made, this 4th request exceeds limit and is rejected.Final Answer:
Request at second 9 -> Option AQuick Check:
4th request in 10s window = rejected [OK]
- Ignoring requests older than 10 seconds
- Allowing all requests without limit
- Counting requests incorrectly
Solution
Step 1: Understand fixed window behavior
Fixed window counts requests in fixed intervals, resetting count at window end.Step 2: Identify burst cause
Requests near end of one window and start of next can both be allowed, causing bursts.Final Answer:
Fixed window resets counters abruptly causing bursts -> Option DQuick Check:
Fixed window reset causes bursts [OK]
- Confusing sliding window with fixed window
- Blaming rate limit value instead of algorithm
- Ignoring window reset behavior
Solution
Step 1: Consider scalability and accuracy needs
Millions of users require distributed design to avoid bottlenecks and reduce latency.Step 2: Evaluate options
Centralized fixed window causes bottleneck; client-only token bucket is insecure; no rate limiting risks overload. Distributed sliding window with local caches and sync balances accuracy and scalability.Final Answer:
Distributed sliding window using local caches and periodic sync -> Option BQuick Check:
Distributed sliding window = scalable + accurate [OK]
- Choosing centralized approach causing bottlenecks
- Relying on client-only enforcement
- Ignoring rate limiting and risking overload
