Rate Limiter Simulator

Runs in browser

Interactive playground to visualize rate limiting algorithms

How to Use

Select an algorithm and send requests.

You will see:

  • Visual Bucket/Window State
  • Request Timeline Graph
  • Allowed/Blocked Statistics
Total Requests
0
Current RPS
0
Allowed
0
Blocked
0

State

0.0 / 10

Request Timeline

Send requests to see timeline

Allowed/sec
Total/sec

Request Log

0 events

Waiting for requests...

The Definitive Guide to Rate Limiting

Rate limiting is a fundamental defense mechanism in distributed systems and API design. It controls the rate of traffic sent or received by a network interface controller, acting as a crucial safeguard against Denial of Service (DoS) attacks, brute-force password attempts, and unintentional cascading failures (retry storms) from well-meaning clients.

Core Rate Limiting Algorithms

There is no "perfect" rate-limiting algorithm. Each approach makes calculated trade-offs between memory efficiency, strictness, and its ability to absorb sudden bursts of traffic. Modern systems often use a combination of these algorithms depending on the endpoint's strictness requirements.

1. Token Bucket

Concept: Imagine a bucket with a maximum capacity. Tokens are added to the bucket at a consistent rate. Each incoming request must "spend" a token to be processed. If the bucket is empty, the request is dropped (429 Too Many Requests).

  • Pros: Extremely simple to implement. Highly memory efficient. It allows bursts of traffic up to the maximum capacity of the bucket, which is excellent for typical web traffic patterns.
  • Cons: A suddenly aggressive client can drain the entire bucket in milliseconds, starving subsequent legitimate requests until tokens refill.
  • 🏢 Used by: Amazon EC2 API, Stripe (for most endpoints).

2. Leaky Bucket

Concept: Similar to a physical leaky bucket, requests are dumped into a queue (the bucket) from the top at any speed. The server processes requests from the bottom of the bucket at a strictly constant, smoothed rate (the leak).

  • Pros: Guarantees a completely stable, predictable outflow rate. Perfect for protecting easily-overwhelmed legacy systems or strict downstream SLAs.
  • Cons: Cannot handle bursts. If a burst fills the queue with old requests, fresh and potentially more urgent requests are instantly dropped because the queue is full.
  • 🏢 Used by: Shopify, Network Traffic Shaping (QoS).

3. Fixed Window Counter

Concept: Time is divided into strictly rigid windows (e.g., 00:00 to 00:01, 00:01 to 00:02). Each window has an independent counter. When a request arrives, the counter for the current time window increments.

  • Pros: The absolute easiest to implement. Requires only a single counter per user in Redis (using `INCR` and `EXPIRE`).
  • Cons: The Boundary Problem. A client can send 100 requests at 00:00:59, and another 100 at 00:01:00. This results in 200 requests hitting the server in a 2-second span, bypassing the intended limit of 100/minute.

4. Sliding Window Log

Concept: To solve the boundary problem, we record the exact millisecond timestamp of every single request in a sorted set (like Redis ZSET). To check limits, we drop all timestamps older than 1 minute, and count the remaining items.

  • Pros: Perfectly accurate. It completely eliminates the boundary problem seen in Fixed Window algorithms.
  • Cons: Extremely memory intensive. Storing a timestamp for every single request across millions of users consumes vast amounts of RAM, making it impractical for massive scale.

5. GCRA (Generic Cell Rate Algorithm)

Concept: An esoteric but highly efficient variation of the Leaky Bucket. Instead of tracking tokens or timestamps, GCRA tracks a single "Theoretical Arrival Time" (TAT). If a request arrives before its scheduled TAT (minus a burst tolerance), it's rejected.

  • Pros: Unbelievably memory efficient—requires tracking only one floating-point number per user. Provides mathematically perfect cell-rate constraints.
  • Cons: Complex to understand and debug. Implementations require tight floating-point arithmetic synchronicity across distributed nodes.
  • 🏢 Used by: Kong API Gateway, advanced telecom switches.

Distributed Rate Limiting Challenges

In modern architectures, a single application server is never enough. Traffic hits load balancers and is distributed across dozens of stateless nodes. Implementing a rate limiter across a distributed cluster introduces severe challenges:

1. Race Conditions

If two application nodes concurrently check Redis, they both might see "tokens = 1" and both allow the request, dropping the count to -1.

Solution: All Redis operations (check limits, calculate time, deduct token) must be executed atomically using Lua Scripts injected directly into the Redis engine.

2. Network Latency

If an API Gateway has to make a synchronous network call to a centralized Redis cluster for every single incoming request to verify limits, latency doubles.

Solution: Use "Local In-Memory Caching" combined with asynchronous syncs (e.g., node syncs its local counts to Redis every 1 second). This gives up some strict accuracy in exchange for massive latency improvements.

Best Practices for API Design

  • Use Standard Headers: Always return X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset HTTP headers so clients know exactly when they can retry.
  • HTTP 429 Status: Never return a 500 or 400 for rate limits. The standard enforces HTTP Status 429 Too Many Requests.
  • Multi-Tiered Limits: Protect APIs at multiple layers. E.g., 10,000 requests/IP/minute at the Cloudflare layer to prevent DDoS, and 100 requests/USER/minute at the Application layer for tier enforcement.

Further Reading