Rate Limit Cascade
criticalSummary
When a downstream service begins rate limiting requests from an upstream service, the upstream's retry logic with insufficient backoff amplifies the request rate : exceeding the rate limit further and potentially pushing the rejection downstream to other upstream callers, producing a cascade of rate-limited retries across the call graph.
Description
Rate limiting is intended to protect a service from overload. When rate limiting begins, callers receive 429 Too Many Requests. Well-behaved callers back off. Poorly-behaved callers (or callers without explicit 429 handling) retry immediately or with minimal delay, increasing the request rate beyond the limit: the exact opposite of the intended behavior.
Cascade mechanics: 1. Service B begins rate limiting Service A (A is over quota or B is under load) 2. A's retry logic retries the 429 immediately or within 1 second 3. A now sends 2× requests (original + retry) to B 4. B rate-limits more requests; A retries more 5. A's request backlog grows; A begins to exhaust its own connection pool and
thread pool waiting for successful responses from B
6. A starts returning errors to its own callers (Service C) 7. C retries its requests to A, compounding A's load further
This pattern is particularly common when: - The retry library handles all non-2xx responses with immediate retry - No distinction is made between retryable (503, 502) and non-retryable (429) status codes - The Retry-After header from the 429 response is ignored
A rate-limit cascade can cause a brief transient rate limit event to become a prolonged partial outage across multiple services in the dependency graph.
Characteristics
Triggers
- ·Downstream service begins rate limiting without the upstream implementing proper 429 handling
- ·Traffic spike causes the upstream to exceed its downstream quota
- ·Downstream reduces its rate limit quota without notifying upstreams
- ·Retry middleware configured to retry all 5xx and 4xx responses uniformly
Detection Signals
Mitigation Strategies
When receiving a 429, extract the Retry-After header and wait the specified duration before retrying. If 429 responses persist, open a circuit breaker for that dependency rather than continuing to retry. The circuit breaker prevents the retry amplification loop.
Configure retry logic with exponential backoff (delay doubles on each attempt) and random jitter (prevent synchronized retries from multiple instances). A starting backoff of 100ms × 2^attempt + rand(0, 100ms) prevents immediate re-requests. Maximum backoff should be 10–30 seconds.
Implement a client-side rate limiter for calls to each downstream dependency. Set the limit to the downstream's documented quota. Requests above the limit are queued or rejected client-side before being sent: preventing rate limit events entirely by never exceeding the downstream's quota.
Recovery Steps
- 1.Identify the origin rate limit event in downstream metrics (first 429 responses)
- 2.Reduce upstream retry rate or apply circuit breaker to the 429-returning dependency
- 3.Check Retry-After headers in 429 responses and configure callers to honor them
- 4.Monitor 429 rate across all services in the dependency chain to identify propagation path
- 5.Post-incident: implement 429-specific handling in all retry middleware
Estimated recovery time: Stopping the retry amplification provides immediate relief (seconds). Root cause fix (implementing proper 429 handling) requires a code deployment (hours to days). Downstream capacity recovery (if the downstream was overloaded) takes minutes after upstream retry rate drops.
Affected Systems
Patterns
Technologies
Basis
Rate limit cascade mechanics are documented in AWS architecture best practices, Netflix Hystrix documentation, and Google SRE book chapter on handling overload; the retry-amplification pattern is a well-understood failure mode in distributed systems
Run This Failure
Blast radius analysis for this failure mode within each scenario that carries it.
Related Architecture Knowledge
Inbound: affects this entity
Rate limiting enforced at the API boundary prevents the retry amplification loop that causes rate limit cascades by ensuring callers never exceed the downstream quota in the first place.
Full relationship →Used In Architecture Scenarios
Multi-Tenant SaaS
A multi-tenant API gateway providing authentication, distributed rate limiting, request routing, payload transformation, and per-tenant usage analytics for API publishers. The hot path: authentication check, rate limit evaluation, and routing decision: must complete in under 1ms using Redis-only data structures to avoid proxying latency dominating upstream service response time. PostgreSQL stores tenant configuration, subscription plans, and API key definitions. Kafka receives API usage events for downstream billing and analytics. Configuration changes (rate limit updates, routing rule edits) must propagate to all gateway replicas without restart.
Event-Driven System
A multi-channel notification delivery architecture that accepts upstream business events (order placed, payment received, comment posted, threshold alert triggered) and routes them to per-channel delivery workers (push via FCM/APNs, email via SendGrid, SMS via Twilio, in-app via WebSocket). Kafka carries raw business events from upstream producers. RabbitMQ handles per-channel fan-out with separate exchanges and queues per delivery channel, isolating email queue backlog from push notification delivery. PostgreSQL provides durable notification state tracking (sent, failed, bounced, suppressed). Redis enforces per-user rate limiting (notification frequency caps to prevent fatigue) and stores deduplication tokens to prevent duplicate sends across retry attempts. The inbox pattern on the consumer side ensures idempotent delivery even when Kafka produces duplicate events.