Skip to main content

Someone wanted to learn this too, so Grasp built them a personal learning path.

You can keep exploring this one or create your own

Fixed-Window Rate Limiting: Implementation & Pitfalls

Hello! Welcome back.

In our last lesson, we implemented the token bucket algorithm, a sophisticated method for rate limiting that gracefully handles traffic bursts while enforcing a sustained average rate. We saw how its flexibility makes it a popular choice for production systems.

Today, we shift our focus to a different, much simpler algorithm. While token bucket is powerful, its implementation can be more complex. Sometimes, a simpler approach is sufficient, but it comes with its own set of trade-offs.

The learning outcome for this lesson is to implement a fixed-window counter rate limiter, explaining its memory efficiency and boundary condition issues. We will explore its core mechanics, implement it using Python and Redis, and critically analyze its primary weakness.


1. The Fixed-Window Counter Algorithm

The fixed-window counter is one of the most straightforward rate limiting algorithms. The core idea is to divide time into fixed intervals, or "windows," and maintain a counter for each client within each window.

For a clear explanation of this concept and its place in a system design context, please watch the following segment from an interview breakdown by a former Meta staff engineer.

Design a Distributed Rate Limiter w/ a Ex-Meta Staff Engineer: System Design Breakdown

In 'Design a Distributed Rate Limiter', the fixed-window counter is presented as the simplest starting point for a rate limiting algorithm.

Watch the section on the Fixed Window Counter (00:23:20 - 00:25:18). Pay close attention to: The basic mechanism: a counter per user that resets at the start of each new window. The data structure used for implementation: a simple hash table. The critical drawback mentioned: the boundary effect.

To see this in action, the next video provides a great animation that visualizes how requests are handled and what happens at the window boundaries.

Design Rate Limiter (LLD) - Token Bucket, Fixed & Sliding Window with Thread Safety

The video 'Design Rate Limiter (LLD)' offers a practical demonstration of the fixed-window algorithm.

Watch from 00:11:33 to 00:13:44. The animation clearly shows requests being counted within a window and then rejected. Crucially, it visualizes the traffic spike that can occur at the boundary between two windows.

As both videos highlight, the algorithm's main appeal is its simplicity. But its primary flaw, the boundary burst issue, is significant and is something we need to analyze carefully.


2. Implementation with Python and Redis

For a distributed system like the ones you build at AWS, state must be managed centrally. An in-memory counter on a single application instance won't work, as it doesn't provide a global view of a client's requests. Redis is an excellent tool for this, providing fast, centralized, and atomic operations.

Let's walk through how to implement a fixed-window counter using Redis. The core of the logic relies on two Redis commands:

  • INCR: Atomically increments a counter. If the key doesn't exist, it's created and set to 1. This atomicity is crucial for handling concurrent requests without race conditions.
  • EXPIRE: Sets a time-to-live on a key. This is perfect for ensuring our counters for old windows are automatically cleaned up, which is key to the algorithm's memory efficiency.

The following article provides a fantastic walkthrough of this logic. While the code is in TypeScript, the principles are identical.

Build 5 Rate Limiters with Redis: Algorithm Comparison Guide

The guide 'Build 5 Rate Limiters with Redis' from Redis's official site details a robust implementation of the fixed-window counter.

Please read the 'Code walkthrough' section under '1. Fixed window counter'. Focus on the four key steps explained: Window key derivation: Understand how Math.floor(now / windowSeconds) is used to create a unique key for each time window. Atomic increment: The role of INCR in preventing race conditions. Expiry on first request: The clever use of EXPIRE to manage memory automatically. Retry-after calculation: How TTL can be used to provide helpful feedback to the client.

Your Turn: Python Implementation

Now, let's translate that logic into Python. The article below provides a clean Python implementation that mirrors the logic from the Redis guide.

How to Implement API Rate Limiting Strategies - OneUptime

The blog post 'How to Implement API Rate Limiting Strategies' from OneUptime gives a direct Python and Redis implementation.

Review the Python code block under the 'Fixed Window Algorithm' section. Notice how it implements the same logic we just studied: it constructs a window-specific key, uses r.incr(), and sets r.expire() on the first hit.

Based on this example, try to write your own is_allowed_fixed_window function.

Requirements:

  1. The function should accept client_id, max_requests, and window_seconds.
  2. It should connect to a local Redis instance.
  3. Implement the logic to create a window-specific key. For example: f"rate_limit:{client_id}:{current_window}".
  4. Use redis-py's incr and expire methods to manage the count.
  5. Return True if the count is within the limit, and False otherwise.

This exercise will solidify your understanding of how to apply the algorithm in a distributed-friendly way.


3. Analyzing the Trade-offs

Your preference for analyzing trade-offs is crucial for a senior engineer. Let's break down the pros and cons of the fixed-window algorithm, which are central to its learning outcome.

Memory Efficiency (Pro)

The fixed-window counter is extremely memory-efficient. For each client making requests, you only need to store one key in Redis per active time window.

For example, with a limit of 1000 requests per hour per user:

  • A user makes a request at 10:15 AM. A key like ratelimit:user123:10 is created with a value of 1 and an expiry of one hour.
  • Subsequent requests before 11:00 AM just increment this single key.
  • At 11:05 AM, a new key ratelimit:user123:11 is created.
  • The old key ratelimit:user123:10 automatically expires around 11:15 AM.

This is highly efficient compared to algorithms that need to store a timestamp for every single request.

Boundary Condition Issues (Con)

The major drawback is the potential for a "burst attack" at the window boundary.

Fixed Window Algorithm Illustration
This diagram illustrates the fixed-window algorithm. Notice in the 10:42-10:43 window, the 11th request is dropped. The key issue is that a client can exhaust their quota at the end of one window (e.g., at 10:42:59) and immediately start a new quota at the beginning of the next (e.g., at 10:43:00), effectively doubling their rate over a short period.

Let's use a concrete example:

  • Rule: 100 requests per minute.
  • Window 1: 12:00:00 to 12:00:59.
  • Window 2: 12:01:00 to 12:01:59.

A client can make 100 requests at 12:00:59 (all allowed) and another 100 requests at 12:01:00 (all allowed). The result is 200 requests in about one second, which can easily overwhelm a downstream service. This happens because the counter abruptly resets to zero at the boundary, with no memory of the recent past.

This lack of precision makes the fixed-window algorithm unsuitable for services that require strict control over request rates.


4. Algorithm Comparison

So, how does the fixed-window counter stack up against the token bucket we learned previously, and other alternatives?

The comparison table from the Redis article provides a perfect summary.

Build 5 Rate Limiters with Redis: Algorithm Comparison Guide

The 'Comparison' section of the Redis article offers a concise summary of the trade-offs between five different rate limiting algorithms.

Please study the comparison table. Focus on the rows for 'Fixed window' and 'Token bucket'. Note their differences across: Memory per client: 1 key for Fixed Window vs. 1 key (with 2 fields) for Token Bucket. Both are very efficient. Accuracy: Approximate for Fixed Window vs. Exact for Token Bucket. Burst behavior: Fixed Window allows a 2x burst at boundaries, whereas Token Bucket allows for controlled bursts. Complexity: Low for Fixed Window vs. High for Token Bucket (especially since it often requires a Lua script for atomic operations in Redis).

This table is a valuable reference. The choice between these algorithms depends entirely on the specific requirements of your service:

  • Need something simple and "good enough" for low-stakes use cases like login attempt throttling? A fixed-window counter is often fine.
  • Need to protect a critical, high-throughput service and ensure a smooth traffic pattern? A token bucket is a much safer and more robust choice.

Conclusion

In this lesson, we explored the fixed-window counter algorithm, the simplest form of rate limiting. We learned its mechanics, implemented it with Python and Redis, and, most importantly, analyzed its strengths and weaknesses.

Key Takeaways:

  • Fixed-Window Counter: Divides time into fixed intervals and uses a simple counter for each client within that interval.
  • Memory Efficiency: It's highly memory-efficient, requiring only one key per client per active window in a system like Redis. The EXPIRE command makes cleanup automatic.
  • Atomicity: Using INCR in Redis is essential for a correct, race-condition-free implementation in a distributed environment.
  • Boundary Issue: Its primary weakness is allowing clients to send a burst of traffic (up to 2x the limit) by straddling the boundary between two windows. This makes it imprecise and potentially unsafe for sensitive systems.

Next Lesson Preview

The boundary issue of the fixed-window counter is a significant problem. In our next lesson, we will directly address it by exploring a more accurate, but more memory-intensive, alternative. You will implement a sliding-window log rate limiter, detailing how it improves accuracy over the fixed-window approach. This will continue our journey through the trade-offs of rate-limiting design.

Can't find a good explanation? Sign up and we'll make it for you

Sign up