Reviewed by 6 specialized AI reviewers. Explore the diagram and the full per-section feedback below.
Loading diagram…
Distributed Rate Limiting System Design
Overview
Clients send requests through the Application Gateway. The Rate Limiter runs inside the gateway layer to avoid additional network hops and enforce limits before requests reach downstream services.
The system supports multiple levels of rate limits:
User level: user123 -> 1000 requests / 5 minutes
API level: /payments -> 50K requests/sec
Tenant level: tenantA -> 1M requests/hour
Global level: entire platform limit
A request is allowed only if it passes all applicable rate limit checks.
Token Bucket Algorithm
For user/API/tenant limits we use the Token Bucket algorithm.
Each bucket maintains:
{
"tokens": 500,
"last_refilled_timestamp": 1690000000
}
For every incoming request, the rate limiter executes a Redis Lua script.
The Lua script:
Calculates tokens generated since the last refill.
Updates the bucket size up to the maximum capacity.
Checks if tokens are available.
Consumes one token if allowed.
Updates the timestamp.
Since Redis Lua scripts execute atomically, concurrent requests cannot overspend tokens.
Example:
user123:
capacity = 1000
refill rate = 1000 / 5 minutes
If tokens are available:
ALLOW
Otherwise:
429 Too Many Requests
The response includes:
X-RateLimit-Limit
X-RateLimit-Remaining
Retry-After
Multiple Rule Evaluation
A request can match multiple rules:
User Rule:
user123 -> 1000/min
API Rule:
/payments -> 50K/sec
Tenant Rule:
tenantA -> 1M/hour
The rate limiter evaluates all applicable buckets.
The request succeeds only if all checks pass.
Global Rate Limiting
A global rule cannot be enforced by calling Redis for every request because the global Redis key would become a bottleneck.
Instead, we use a lease-based token allocation mechanism.
The global Redis maintains the global bucket:
Global limit:
5M requests/sec
Rate limiters request token leases:
Gateway-1 -> 10000 tokens
Gateway-2 -> 10000 tokens
Gateway-3 -> 10000 tokens
Redis atomically deducts these tokens:
global_tokens -= leased_tokens
The gateway keeps the leased tokens in memory and performs local rate limiting.
Redis is only contacted when the lease is exhausted.
Preventing Global Token Over Allocation
Each lease has:
lease_id
region
allocated_tokens
expiry_time
Lease allocation happens atomically in Redis.
Redis ensures:
available_tokens + active_leases <= global_capacity
A lease has a short expiry window. If a gateway crashes with unused tokens, those tokens become invalid after expiry and are returned to the available pool.
This prevents one failed region from permanently holding global quota.
Handling Hot Keys
A large tenant or popular API key can become a hot key.
Example:
Region traffic:
300K RPS
tenant123:
200K RPS
All requests targeting:
tenant123
would hit the same Redis bucket.
To avoid this:
Requests for the same tenant are routed using consistent hashing to the same gateway.
The gateway maintains local token state.
High-volume tenants use the same lease mechanism as global limits, where quota is distributed to gateways.
This removes Redis from the hot request path.
Rule Management and Consistency
Rules are stored in ETCD.
The control plane updates ETCD, and gateways maintain watches on rule changes.
Each rule contains a version:
rule:
{
limit: 500,
version: 25
}
When a new version is published, gateways atomically replace their local rule snapshot.
During propagation, some gateways may temporarily have an older version. To maintain consistency, every request is evaluated against the gateway's latest available snapshot, and stale gateways refresh their configuration when they detect version lag.
For critical rule changes, gateways can force-refresh rules before allowing traffic.
Regional Architecture and Scaling
Assume:
Total traffic:
1M RPS
Regions:
4
Peak region traffic:
300K RPS
A gateway instance handles:
20K RPS
Required gateways per region:
300K / 20K = 15 gateways
Each region has:
API Gateway + Rate Limiter fleet
Redis cluster
ETCD cluster
Redis capacity:
Single Redis:
100K operations/sec
For 300K regional traffic:
4-5 Redis nodes per region
are deployed for capacity and redundancy.
Global Redis Network Partition Handling
The global Redis is only used for quota allocation, not every request.
If a region loses connectivity to global Redis:
Existing leases continue to work.
The region consumes already allocated tokens.
New leases cannot be acquired.
To avoid unlimited usage, each region has a predefined emergency quota.
After connectivity is restored:
Region reports consumption.
Global quota state is reconciled.
New leases are adjusted.
This allows availability while still maintaining approximate global enforcement.
Circuit Breaker
A circuit breaker exists between the rate limiter and Redis.
States:
Closed:
Redis healthy
Open:
Redis failing
Half-open:
Send limited test requests
If Redis latency increases or failures occur:
Circuit opens.
Rate limiter uses cached rules and fallback limits.
Periodically checks Redis health.
Returns to normal after recovery.
Want this kind of feedback on your own design?
Draw your architecture for Rate Limiter and get an instant hire/no-hire signal from 6 specialized AI reviewers — free to start.