Back
LearnSystem Design PlaybookDesign a Rate Limiter

Design a Rate Limiter

2 min read

Design a Rate Limiter

A rate limiter caps how many requests a client can make in a window — protecting against abuse, runaway clients and cost overruns.

1. Requirements

  • Limit per client (API key / user / IP), e.g. 100 req/min.
  • Low latency (it's on every request), accurate, works across a distributed fleet.
  • Return 429 Too Many Requests + Retry-After when exceeded.

2. Algorithms

Algorithm Idea Trade-off
Token bucket Bucket refills at a rate; each request takes a token Allows bursts; the go-to default
Leaky bucket Requests drain at a fixed rate Smooths bursts, adds latency
Fixed window Count per calendar minute Simple; 2× burst at the boundary
Sliding window Weighted blend of two windows Good accuracy/memory balance

3. Distributed design

The counter must be shared — otherwise each server allows the full limit.

Request ─▶ App ─▶ Redis (INCR key, check limit) ─▶ allow / 429
key   = "rl:{user}:{window}"
count = INCR key
if count == 1: EXPIRE key 60
if count > limit: return 429

Use a Lua script so "check + increment + set TTL" is atomic, avoiding races.

4. Deep dives

  • Where: at the API gateway / edge so bad traffic is rejected early.
  • Trade-off: central Redis adds a hop and a dependency — shard it or cache buckets locally.
  • Fairness: separate limits per tier (free vs paid).

Takeaway: token bucket + atomic Redis counter is the standard, interview-ready rate limiter.

Tip