TubeSum ← Transcribe a video

Rate Limiter System Design: Token Bucket, Leaky Bucket, Scaling

0h 07m video Published Oct 14, 2025 Transcribed Aug 6, 2026 B ByteByteGo
Intermediate 5 min read For: Software engineers and system design interview candidates with basic knowledge of distributed systems.
AI Trust Score 75/100
⚠️ Average / Some Fluff

"Delivers a thorough system design walkthrough as promised, though the sponsor segment adds minor padding."

AI Summary

This video provides a comprehensive system design walkthrough for building a rate limiter, covering core algorithms like fixed window, token bucket, and leaky bucket, along with architectural decisions for scaling and avoiding race conditions. It explains how rate limiters protect APIs from overload while ensuring fair access, and discusses implementation strategies including client-side, server-side, and middleware approaches.

[00:03]
What is a Rate Limiter?

Rate limiters control how many requests a client can make to an API in a given time window, protecting systems from overload while maintaining fair access for legitimate users.

[00:17]
Core Requirements

The system should limit requests based on configurable rules (e.g., 100 requests per minute per user), reject with HTTP 429 when exceeded, include headers for remaining and reset time, introduce minimal latency (under 3ms P95), and be highly available across multiple servers.

[00:58]
Fixed Window Counting

Simplest approach: divide time into fixed windows (e.g., 1 minute). Each user has a counter that resets at window start. When the counter hits the limit, additional requests are rejected until the next window.

[01:27]
Storage Considerations

Database is too slow for counters. In-memory storage on a single server is fast but doesn't work across multiple servers, leading to separate counters and bypassing limits. Redis solves this as a shared in-memory data store.

[02:37]
Fixed Window Flaw

A user can make 100 requests in the last 10 seconds of a minute and 100 more in the first 10 seconds of the next minute, totaling 200 requests in 20 seconds, violating the intended limit. This edge case occurs at every window boundary.

[03:06]
Token Bucket Algorithm

Industry standard (used by AWS, Stripe). A bucket holds tokens added at a steady rate. Each request consumes one token; if none left, reject. Tokens accumulate during quiet periods, allowing legitimate bursts while maintaining overall rate.

[04:03]
Token Bucket Parameters

Bucket capacity determines burst size; refill rate determines sustained throughput. Example: capacity 100, refill 100/min allows up to 100 requests instantly, maintaining 100/min long-term.

[04:33]
Implementation Placement

Options: client-side (untrusted), server-side (mixes with business logic), middleware (dedicated service like API gateway). Middleware offers best balance of control and simplicity for most systems.

[05:44]
System Architecture

Rate limiting rules stored in a configuration service. Middleware fetches rules, stores token bucket state in Redis. On request, identifies user, checks tokens, decrements if available, else returns 429 with retry header.

[06:26]
Scaling and Race Conditions

Multiple servers can read the same counter value, leading to lost updates. Solved with atomic operations in Redis using Lua scripts that bundle read, check, and increment into a single unit.

The video provides a solid foundation for designing a rate limiter, covering key algorithms, storage, and scaling considerations. It emphasizes the token bucket as the industry standard and highlights the importance of atomic operations for consistency in distributed systems.

Mentioned in this Video

Tutorial Checklist

1 00:17 Define requirements: configurable limits, HTTP 429 responses, headers, low latency, high availability.
2 00:58 Implement fixed window counting with counters resetting each window.
3 01:27 Use Redis for shared in-memory counters across servers.
4 03:06 Implement token bucket algorithm with capacity and refill rate.
5 04:33 Choose middleware placement for rate limiting logic.
6 05:44 Store rules in config service, use Redis for token state, handle requests via middleware.
7 06:26 Use atomic operations (Lua scripts) in Redis to prevent race conditions when scaling.

Study Flashcards (7)

What is the primary purpose of a rate limiter?

easy Click to reveal answer

To control how many requests a client can make to an API in a given time window, protecting systems from overload while maintaining fair access.

00:03

What HTTP status code is used when a rate limit is exceeded?

easy Click to reveal answer

HTTP 429

00:31

What is the main flaw of the fixed window algorithm?

medium Click to reveal answer

It allows a user to make 100 requests at the end of one window and 100 at the start of the next, totaling 200 requests in a short period, violating the intended limit.

02:37

How does the token bucket algorithm allow bursts?

medium Click to reveal answer

Tokens accumulate during quiet periods, allowing legitimate traffic bursts while maintaining the overall rate limit.

03:49

What are the two parameters of the token bucket algorithm?

easy Click to reveal answer

Bucket capacity (determines burst size) and refill rate (determines sustained throughput).

04:03

Why is client-side rate limiting not recommended?

medium Click to reveal answer

Clients cannot be trusted to enforce their own limits; malicious users can modify code or bypass restrictions.

04:47

How can race conditions be prevented in a distributed rate limiter?

hard Click to reveal answer

By using atomic operations in Redis, such as Lua scripts that bundle read, check, and increment into a single indivisible unit.

06:53

💡 Key Takeaways

📊

Token Bucket as Industry Standard

It's the algorithm used by major companies like AWS and Stripe, making it a critical concept for system design interviews.

03:06
💡

Token Accumulation Enables Bursts

This insight explains how the token bucket elegantly handles traffic spikes without violating rate limits.

03:49
🔧

Atomic Operations Prevent Race Conditions

A key technical solution for maintaining consistency in distributed systems, essential for scaling.

06:53

[00:03] many requests to GitHub, Stripe or AWS and your requests get rejected. How do this system work? Ray limiters control how many requests a client can make to an API in a given time window. They protect systems from overload while

[00:17] maintaining fair access for legitimate users. Let's tackle the core design challenges. Let's go over the requirements first. The system should limit incoming requests based on configurable rules like 100 API requests

[00:31] per minute per user. When limits are exceeded, the system should reject requests with HTTP 429 and include helpful headers showing rate limit remaining and reset time. The system should introduce minimal latency

[00:45] overhead, say under 3 millisecond P95 per check. The system should be highly available and accessible by multiple servers. Now that we understand what we need to build, let's start with the simplest

[00:58] approach, fixed window counting. We divide time into fixed windows like one minute intervals. Each user gets a counter that resets at the start of each window. Here's how it works. A user is allowed 100 requests per minute. At the

[01:12] start of each minute, their counter resets to zero. Each request increments to counter. When they hit 100 requests, we reject additional requests until the next minutes begins. We need to store these counters somewhere fast. The

[01:27] database is too slow for this. Today's video is sponsored by Warped, the best way to code with AI agents. Too often, agents write code that's almost right, leaving developers stuck debugging instead of shipping. Warp is different.

[01:41] Rank top of terminal bench and bench verified. Warps agent understands your context and writes production ready code out of the box. Prom, review, and refine all in one interface. No context switching, no wasted time. You stay in

[01:55] control and it pays off. On average, users are saving over an hour a day with Warp. Download Warp by clicking the link in the description. We're adding a database query to every request, which could overload the very

[02:09] system we're trying to protect. What about in-memory storage and this server? This would be very fast, but it only works for a single server. When we scale to multiple servers, each server would have its own separate counters. A user

[02:22] could make 100 requests to server A and 100 requests to server B, effectively getting 200 requests per minute instead of 100. Reddit solves both problems. Is an in-memory data store that's shared across all our servers. Reddis provides

[02:37] primitives to increment counters and reset them automatically. But fix window have a critical flaw. Consider this scenario. A user makes 100 requests in the last 10 seconds of a minute, then 100 more requests in the first 10

[02:51] seconds of the next minute. Both bursts are within the 100 requests per minute limit individually, but they've made 200 requests in just 20 seconds, which clearly violates the intended ray limit. This edge case happens at every window

[03:06] algorithm. The token bucket algorithm solves the fixed window problem. It's the industry standard used by companies like AWS and Stripe. Think of it like this. Imagine a bucket that hosts tokens. New tokens are

[03:21] added at a steady rate. Each request consume one token. When there are no tokens left, we reject the request. Let's see how this fixes our window boundary problem. We set a bucket capacity of 100 tokens that refills at

[03:35] 100 tokens per minute. During quiet periods, tokens accumulate. When user makes burst requests across window boundaries, they consume accumulated tokens but can't exceed the refill rate over time. The key insight is that

[03:49] tokens accumulate during quiet period. This allow legitimate traffic bursts while maintaining the overall rate limit. A user can game the system by timing the request to window boundaries. The algorithm uses two parameters.

[04:03] Bucket capacity determines burst size and refill rate determines sustained throughput. A capacity of 100 with a refill rate of 100 per minute allows up to 100 requests instantly that maintains exactly 100 requests per minute

[04:17] long-term. There are other algorithms like sliding window logs, sliding window counters, and leaking buckets that solve the fixed window problem differently. balance between simplicity and effectiveness for most use cases. Now

[04:33] that we have our algorithm, we need to decide where to implement it in our options for where to place our ray limiter. Client side ray limiting puts the logic in client applications, but we can't trust clients to enforce their own

[04:47] limits. Malicious users can modify the code or bypass restrictions entirely. Serverside ray limiting embeds the logic in our application code. This gives us complete control over the algorithm and keeps everything in one place. The

[05:02] downsides is that ray limiting gets mixed with business logic and each service needs its own implementation. Middleware ray limiting uses a dedicated service between clients and the APIs. This could be an API gateway, a reverse

[05:16] proxy or a custom service. This keeps ray limiting separate from business logic and provides a single place to manage policies. The trade-off is an increase in system complexity. Which should we choose? It depends on our

[05:29] situation. If we already have an API gateway handling authentication, adding rate limiting there makes sense. If we need a custom algorithm, server side gives us flexibility. For most systems, middleware offers the best balance of

[05:44] control and operational simplicity. Our system architecture looks like this. We store ray limiting rules in a configuration service. These rules define limits like premium users get a th00and requests per hour or free users

[05:58] get 100 requests per hour. The middleware fetches these rules and stores token bucket state in Reddus. When a request arrives, the middleware identifies the user, fetches their token bucket from Reddus and checks if tokens

[06:11] are available. If yes, it decrements the token count and forwards the request to API servers. If no token remains, it returns HTTP 429 with header showing when the user can retry. This works great for a single rail limited server.

[06:26] But what happens when we need to scale to multiple servers, we run into race conditions. Here's what happens. Server A reads a counter value of three from radius. At the same time, server B also reads three. Both servers check their

[06:39] limits, decide the request is okay, increment the value to four, and write it back to Reddus. The counter now shows four instead of the correct value of five. We've lost a count. We can solve this with atomic operations. Reddus

[06:53] supports these two lure scripts that bundle the read, check, and increment into a single indivisible unit. This prevents race condition entirely. We've covered the essential building blocks for ray limiters in this video. There

[07:06] are other interesting topics we didn't cover. How do we handle geographic latency with multi-reion deployment? How do we handle hot keys when a few users generate most traffic? How do we upload rate limiting rules without restarting

[07:19] servers? Should the system fail open or fail closed when key components go down? These are all interesting topics worth exploring. Ready to ace your next technical interview? Join our community where we

[07:32] offer comprehensive courses on system design, coding, behavioral questions, machine learning, and object-oriented design. Learn more at byitebico.com.

More from ByteByteGo

View all

⚡ Saved you 0h 07m reading this? Transcribe any YouTube video for free — no signup needed.