Rate Limiting
Rate limiting caps request volume per client, tenant, or endpoint — protecting backends from abuse, accidental loops, and flash crowds.
Introduction
Rate limiting caps request volume per client, tenant, or endpoint — protecting backends from abuse, accidental loops, and flash crowds. Airbnb's public and internal APIs use token-bucket and sliding-window limiters at the edge (Envoy/Kong) and service layer for fair multi-tenant sharing.
Real production story
Airbnb's search API experienced 6-hour degradation when a partner integration shipped a bug: infinite pagination loop hammering /v2/listings at 15k RPS from one API key. No rate limit existed — Elasticsearch cluster yellowed, legitimate guest search slowed globally. Partner unaware until Airbnb ops called.
Platform team deployed tiered rate limits: default 100 RPS/key, burst 200 token bucket; search endpoints stricter 30 RPS; 429 with Retry-After and structured error body. Partners received quota dashboards. Repeat incident capped at partner-only 429s — guest search SLO held. API reliability score became vendor onboarding requirement.
Business problem
Business pressure: Airbnb marketplace connects thousands of partners and mobile clients to shared search and booking infrastructure — one rogue client threatens global guest experience.
- Guest UX: Search latency during trip planning directly impacts booking conversion.
- Partner ecosystem: Limits must be fair, documented, and negotiable for premium tiers.
- Cost control: Elasticsearch and ML ranking are expensive — unbounded queries burn budget.
Architecture overview
Token bucket: steady rate + burst allowance. Sliding window: precise count over window — higher memory. Fixed window: simple but boundary spike risk. Keys: API key, IP, userId, endpoint combo.
- Definition: Reject or delay requests exceeding configured quota.
- When to adopt: All public APIs, expensive endpoints, auth endpoints (anti-brute-force).
- Response: 429 Too Many Requests + Retry-After + X-RateLimit-* headers.
- Operability: Limit config per tier; dynamic override for flash sales.
Architecture motivation
Why architects care: Rate limiting is the outermost bulkhead — rejects overload before it enters the system.
- Force: Shared search cluster cannot scale linearly with buggy client loops.
- Constraint: Limits must be low-latency — cannot add 50ms DB lookup per request.
- Outcome: Edge limiter + service-level quotas + tenant dashboards.
Internal architecture
Airbnb tiered rate limit architecture:
Partner → CDN → API Gateway (Envoy)│RateLimit filterkey: api_key + routealgorithm: token bucketRedis cluster (global counters)│allow → Search BFF → Elasticsearchdeny → 429 { error: "rate_limit_exceeded",retry_after: 12 }Tiers:standard: 100 rps, burst 200premium: 500 rps, burst 1000internal: 2000 rps (mTLS + separate key)
Data flow
Limit check at edge — fail cheap before Elasticsearch.
- Ingress: Extract api_key → hash to Redis slot → INCR / token decrement atomic Lua.
- Allow path: Forward with X-RateLimit-Remaining header for client self-throttle.
- Deny path: 429 without hitting origin — protect expensive downstream.
System design diagram
Two diagrams show the Rate Limiting topology and the primary request/event path used in production at scale.
Production code example
Redis token bucket via Lua — atomic rate limit check with TypeScript caller:
const ALLOW_LUA = `-- token bucket (see distributed.mjs)local tokens = tonumber(redis.call('GET', KEYS[1] .. ':tokens') or ARGV[2])local last = tonumber(redis.call('GET', KEYS[1] .. ':ts') or ARGV[3])local delta = math.max(0, ARGV[3] - last)tokens = math.min(ARGV[2], tokens + (delta / 1000) * ARGV[1])if tokens < 1 then return {0, 0} endtokens = tokens - 1redis.call('SET', KEYS[1] .. ':tokens', tokens)redis.call('SET', KEYS[1] .. ':ts', ARGV[3])return {1, tokens}`;async function checkRateLimit(apiKey: string, route: string, tier: TierConfig) {const bucketKey = `rl:${apiKey}:${route}`;const now = Date.now();const [allowed, remaining] = await redis.eval(ALLOW_LUA, 1, bucketKey, tier.ratePerSec, tier.burst, now,) as [number, number];if (!allowed) {throw new RateLimitError({retryAfterSec: Math.ceil(1 / tier.ratePerSec),limit: tier.ratePerSec,route,});}return { remaining, limit: tier.burst };}
Enterprise case study
Airbnb partner search API rate limits after pagination loop incident.
- Before: 15k RPS from one key; global search degraded 6 hours.
- Decision: Token bucket at Envoy + Redis; tiered quotas; 429 with Retry-After.
- After: Repeat bug isolated to partner 429s; guest search SLO maintained.
Trade-offs
- Strict vs loose limits: Tight limits protect platform; loose limits win partners — tiered contracts.
- Global vs local counters: Redis global accurate but network hop; local approximate per pod faster.
- 429 vs queue: Sync APIs reject; async jobs may delay — different UX contracts.
- False positives: Shared NAT IP hits IP-based limits — prefer authenticated keys.
Security considerations
Rate limiting is primary anti-abuse control for public APIs.
- Auth endpoints: 5/min/IP + captcha escalation — credential stuffing defense.
- Partner keys: Rotate on leak; per-key audit log for forensic.
- DDoS: Edge limit complements WAF — not replacement for network-layer scrubbing.
Scalability analysis
Rate limiter must scale with edge traffic — Redis cluster sharded by api_key hash.
- Horizontal scale: Envoy sidecars local token cache with periodic Redis sync — eventual consistency acceptable for burst.
- Hot key: Mega-partner on dedicated shard or higher local bucket.
- Cost: Limit expensive endpoints aggressively — search 30 RPS vs health 10k RPS.
Failure scenarios
Limiter store down — fail open or closed is a business decision.
- Redis unavailable: Airbnb fails closed on partner routes, fail open on guest mobile with local approximate limit — document asymmetry.
- Clock skew: Sliding window across pods — use Redis TIME or centralized counter.
- Limit bypass bug: Header spoofing — authenticate before trusting api_key.
Staff engineer insights
- Return Retry-After on 429 — good clients self-heal; bad clients get blocked faster.
- Rate limit response body is a product surface — partners integrate against it.
- Expensive endpoint limits are cost architecture, not just security.
Interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1AdvancedQuestionToken bucket vs sliding window log — trade-offs at Airbnb scale?+
Answer
Follow-up
2AdvancedQuestionLimiter Redis down — fail open or closed?+
Answer
Follow-up
3AdvancedQuestionDesign rate limits for flash sale — 10× traffic in 60 seconds.+
Answer
Follow-up
Architecture review questions
- All public and partner APIs have documented rate limits per tier.
- 429 responses include Retry-After and rate limit headers.
- Limiter check at edge before expensive downstream (search, ML).
- Redis/limiter failure mode documented (fail open vs closed per route).
- Auth and password endpoints have strict anti-brute-force limits.
- Partner dashboards show quota usage — proactive before hard 429.
Summary
Rate limiting caps ingress load per client and endpoint — Airbnb production practice uses edge token buckets, tiered quotas, and informative 429 responses to keep guest search healthy when partners misbehave.