Sliding Window Counter: Trading Memory for Fairness
The Boundary Problem Solution
Fixed windows have a gap at boundaries: 200 requests can sneak through in 2 seconds when windows change. Sliding window counters fix this by maintaining a rolling view of time rather than discrete buckets. The key insight is that you can approximate a sliding window using two adjacent fixed windows with weighted counting, getting most of the benefits without storing individual timestamps.
The Analog Clock Analogy
Think of a clock with a moving 60 minute hand. At any moment, you count all requests from the past 60 minutes, not from the top of the hour. At 2:37, you count from 1:37 to 2:37. At 2:38, you count from 1:38 to 2:38. The window is always exactly 60 minutes, but its boundaries continuously shift forward with time.
Weighted Approximation Algorithm
Keep two fixed window counters: current and previous. When a request arrives at 2:37:30 (37.5 minutes into the hour): previous window count is 70, current window count is 40, time elapsed in current window is 37.5 minutes, remaining weight from previous is (60 - 37.5) / 60 = 0.375. Estimated count is 40 + (70 × 0.375) = 66.25. Compare this against your limit (say 100). This approximation assumes uniform distribution of requests within each window.
Why Approximation is Good Enough
The weighted approximation can be off by at most 1 window worth of requests in edge cases where traffic is extremely non uniform. In practice, with typical traffic patterns, error is under 10%. This is acceptable for rate limiting where the goal is protection, not perfect accounting. For billing where exact counts matter, use sliding log instead.
Implementation Trade-offs
Memory: O(2) per user (two counters instead of one). Processing: O(1) per request (read two counters, compute weighted sum). Compared to fixed window, you double the storage but eliminate the boundary burst problem. Compared to sliding log (storing every timestamp), you use dramatically less memory while achieving similar fairness.