This simulator runs a live request stream through three real rate-limiting algorithms — token bucket, fixed window and sliding window — against the exact same traffic, so the difference in behaviour is visible rather than theoretical. Tune the client's send rate, the sustained limit, and the burst capacity or window length, then hit Send burst to see how each algorithm handles a sudden spike: the token bucket absorbs it up to its capacity, the fixed window can let through nearly double the limit right at a window boundary, and the sliding window smooths that boundary burst by blending the previous and current window counts.
Requests travel from client to server as particles; at the gate each one is tested against the active algorithm and turns green (admitted) or red (rejected, HTTP 429). The gate itself visualises the algorithm's internal state: a filling token bucket, a sweeping window ring, or a pair of weighted window bars.
Pick an algorithm, set the client send rate, sustained limit and burst capacity / window length, then click Send burst to inject 24 requests at once and watch how each algorithm's admit/reject pattern differs on the live chart.
A fixed window with a 100-request limit can theoretically admit close to 200 requests in the two seconds spanning a window boundary — 100 at the very end of one window and 100 at the very start of the next — which is exactly why many production gateways default to token bucket instead.
It is the cheapest to implement and reason about, requiring only a single integer counter and a reset timestamp per client, with negligible storage overhead even at massive scale. For rate limits that exist mainly as a coarse abuse-prevention backstop rather than a precise SLA guarantee, the boundary burst weakness is often an acceptable trade-off against its simplicity and low cost.
No, they are near-opposites in effect despite sharing the word 'bucket.' Token bucket allows bursts up to a capacity and rejects or delays only the excess, prioritizing throughput and burst tolerance. Leaky bucket forces a constant output rate regardless of input burstiness by queueing excess requests, prioritizing smoothness and predictability for the downstream system at the cost of added latency.
Most use a shared, low-latency data store — commonly Redis — to hold each client's token count or request timestamps, with atomic increment-and-check operations (e.g., Lua scripts in Redis) to avoid race conditions where two servers both check the counter before either updates it. Some systems trade perfect global accuracy for lower latency by using local approximate counters that periodically synchronize, accepting slightly looser enforcement in exchange for not adding a network round-trip to every request.
HTTP 429 (Too Many Requests) tells the client its request was rejected specifically due to rate limiting rather than a server error or bad input. The accompanying Retry-After header (in seconds, or as a timestamp) tells a well-behaved client how long to wait before retrying, which lets clients implement backoff correctly instead of guessing or retrying immediately and making the overload worse.
By assuming request arrivals are roughly uniform within a window, it can approximate the true rolling count from just the previous window's total and the current window's running total, weighted by how far into the current window the clock has moved. This trades a small amount of accuracy for far less memory than a sliding window log, which must store one timestamp per request.