keepcalculator

06 Numbers and Powers

Redis Sliding Window Counter: How It Works & When to Use

Card No. 06·6468 · Updated · Standard formula, shown below

The calculator on this card is switched off while it is checked. The formula is below, and the worked example shows how to do the sum by hand.

Redis sliding window counter rate limiting tracks the number of requests within a fixed time window that slides forward with each request, giving a precise count of recent activity. You enter the window size and maximum allowed requests, and the system returns a decision to allow or block, along with the current count and remaining time until the window resets. This article explains the mechanics, the exact Redis commands, and the trade-offs so you can decide if it fits your use case.

Formula

This calculator is a conceptual tool: it shows the relationship between the window size and the maximum request count, but the real sliding window counter cannot be reduced to a single arithmetic formula because it depends on the current number of requests in the window. The core logic is:

  • Current count = number of requests whose timestamp is greater than (now – window size).
  • Allowed = 1 if current count < max requests, otherwise 0.
  • Reset time = (oldest request timestamp + window size) – now, or the full window if no requests exist.

In the calculator above, w is the window length in seconds, and m is the maximum allowed requests in that window. The first output is a placeholder that illustrates the decision logic (1 if under the limit, 0 if over) using a simple ratio; the real implementation requires a Redis script that reads the current count.

Worked Example

Suppose you set a window of 60 seconds and a maximum of 100 requests. The calculator shows that with zero current requests, the decision is 1 (allow), the count is 0, and the reset time is 60 seconds. That matches the expected behavior: no requests yet, so the first request is allowed, and the window will fully reset in 60 seconds if no requests arrive.

Now imagine 95 requests have arrived in the last 60 seconds. The current count is 95, which is less than 100, so the next request is allowed. After that request, the count becomes 96. If the count reaches 100, the next request is blocked until the oldest request’s timestamp falls outside the window. The reset time is the time until that oldest request expires.

Background: Why Sliding Window Over Fixed Window?

Rate limiting is essential for APIs, login endpoints, and any shared resource that can be overwhelmed. The simplest approach is a fixed window counter: divide time into discrete buckets (e.g., every minute) and count requests in each bucket. This is easy to implement with a Redis key that increments and expires, but it has a critical flaw: a client can send 100 requests at the end of one minute and another 100 at the start of the next, effectively doubling the rate in a single second. The sliding window counter solves this by not resetting at arbitrary boundaries; instead, the window moves continuously with each request, so the count always reflects the last N seconds.

How the Redis Sliding Window Counter Works

The classic implementation uses a Redis sorted set, where each request is a member with a score equal to the current timestamp (in milliseconds or seconds). The algorithm is:

  1. When a request arrives, record the current timestamp as now.
  2. Remove all members with scores less than now - window_size (these are outside the window).
  3. Count the remaining members.
  4. If the count is less than the limit, add the new request (score = now) and allow the request.
  5. If the count is at the limit, reject the request without adding it.

In Redis, this is typically done with a Lua script to ensure atomicity. The script uses ZREMRANGEBYSCORE to purge old entries, ZCARD to get the count, and ZADD to insert the new member. The script returns the decision and the remaining count. Because the script runs atomically, concurrent requests cannot race and create a burst that exceeds the limit.

When to Use Sliding Window Counter

Choose this method when you need precise, smooth rate limiting and the request rate is moderate. It is ideal for:

  • APIs where clients might burst at the edge of a fixed window.
  • Login or signup endpoints where you want to prevent brute-force attacks without penalizing legitimate users who happen to cross a minute boundary.
  • Scenarios where you need to know the exact remaining count and reset time for headers like X-RateLimit-Remaining.

It is less suitable for extremely high throughput (millions of requests per second) because each request requires a few Redis operations and memory grows with the number of requests in the window. For very high rates, a token bucket or a fixed window with some tolerance is often preferred.

Common Problems and Misconceptions

A frequent misconception is that the sliding window counter is the same as the sliding window log. They are related: the log stores every request timestamp, while the counter (also called a sliding window counter with a sorted set) is exactly that log. Some people use the term “sliding window counter� for a hybrid approach that uses two fixed windows and weights them, but the canonical Redis implementation uses a sorted set.

Another issue is memory usage: if you have a long window (e.g., one hour) and a high limit (e.g., 10,000 requests), you will store up to 10,000 members per key. This is usually acceptable, but you can reduce memory by storing timestamps in seconds instead of milliseconds, and by using a smaller window when possible. Also, be careful with clock skew: if your Redis server and application server have different clocks, the timestamps will be inconsistent. Use a single source of time (e.g., the Redis server’s time) or ensure NTP synchronization.

Comparison: Sliding Window vs. Fixed Window vs. Token Bucket

Here is how the three common algorithms compare:

  • Fixed window: Simple, low memory, but allows double bursts at boundaries.
  • Sliding window counter: Smooth, precise, but uses more memory and is slightly slower due to the sorted set operations.
  • Token bucket: Allows bursts up to a capacity, then refills at a steady rate. It is memory-efficient (just two counters) and good for traffic shaping, but does not give an exact count of requests in the last N seconds.

If you need to allow occasional bursts (e.g., a user can send 10 requests quickly, then 1 per second), token bucket is better. If you need a strict “no more than X requests in any rolling Y seconds� guarantee, sliding window counter is the right choice.

Costs and Performance Considerations

Each request triggers a Lua script that does a range removal, a count, and an add. These are O(log N) operations, where N is the number of stored members. With a window of 60 seconds and a limit of 100, you will have at most 100 members, so each operation is very fast. The main cost is network round-trips and the memory for the sorted set. You can reduce network overhead by using Redis pipelining or by embedding the script in your client. Also, if you have many distinct rate limit keys (e.g., per user), you need to manage key expiration: set an expiry on the key equal to the window size so it is cleaned up automatically.

Safety and Accuracy Tips

When implementing, always use a Lua script to keep the check-and-add atomic. If you do it in two separate Redis commands, a race condition can allow more requests than intended. Also, use the same time unit throughout (e.g., milliseconds) and be consistent between the window size and timestamps. Test with a small limit to verify behavior at the boundary. Finally, consider what happens when the Redis server restarts: the sorted set is lost, so the rate limit resets, which is usually acceptable but should be documented.

Frequently Asked Questions

Q: How does sliding window counter differ from sliding window log?
They are the same thing in Redis if you use a sorted set to store timestamps. Some articles use “log� to emphasize that you store every request, while “counter� might refer to a more memory-efficient approximation that uses two fixed windows. The exact Redis implementation with a sorted set is often called a sliding window log or counter interchangeably.

Q: Can I use a simple Redis key with INCR and EXPIRE for sliding window?
No, that gives you a fixed window. To get a sliding window, you need to know the timestamps of all requests, which requires a sorted set. A hybrid approach uses two fixed windows and weights them, but that is an approximation.

Q: What happens if the request is rejected? Should I still add it to the sorted set?
No, you should only add the timestamp if the request is allowed. If you add it even when rejected, the window will fill up faster and legitimate requests will be blocked. The Lua script should conditionally add only when the count is below the limit.

Q: How do I get the reset time for rate limit headers?
Find the oldest timestamp in the sorted set (using ZRANGE with index 0), add the window size, and subtract the current time. If the set is empty, the reset time is the full window size. This is often done in the same Lua script to avoid extra round trips.

Q: Is sliding window counter suitable for distributed systems?
Yes, Redis is a shared store, so all application instances can use the same key. The Lua script ensures atomicity across instances. However, you must consider network latency and the single point of failure; use Redis Sentinel or Cluster for high availability.

Q: What is the memory overhead per user?
Each request stores a member in the sorted set. For a limit of 100 requests per minute, that is at most 100 members per user. Each member is a timestamp string, so roughly 10-20 bytes plus overhead. For millions of users, this can add up, so consider using a more memory-efficient algorithm if that is a concern.

Related

Formula used
in w | Window size (seconds) | s | 60 | 1 | 86400
in m | Max requests per window | - | 100 | 1 | 1000000
out decision | Allow? (1=yes, 0=no) | - | (m - 0) / (m + 1) | 0
out count | Current requests | - | 0 | 0
out reset | Seconds until reset | s | w | 0

Each line is one input (in, sel, list) or one result (out: label, unit, formula, decimals). How the calculators work

Method: the standard formula for this calculation, rounded as each result states. See how the calculators work or report an error.

More cards in this drawer

The whole Numbers and Powers drawer →