Fixed Window Counter Rate Limiting
A fixed window counter limits requests by counting them inside discrete, fixed-duration intervals. Once the counter reaches the configured limit, additional requests during that window are rejected.
A fixed window limiter divides time into intervals such as 60-second periods. Each interval has its own counter, and a request is accepted only while the counter remains below the configured maximum.
For example, with a limit of 100 requests per minute, requests from 12:00:00 through 12:00:59 belong to one window, while requests from 12:01:00 through 12:01:59 belong to the next. At the boundary, the counter resets for the new window.
A common implementation stores a counter keyed by an identity such as user ID, API key, or IP address. The stored value can include the current window identifier and request count. In a distributed Java service, the counter usually needs shared storage or another coordinated mechanism so multiple application instances enforce the same limit.
The main weakness is the boundary effect. A client can send requests near the end of one window and immediately send another batch at the beginning of the next, producing a short period with substantially more traffic than the nominal rate would suggest.
Key points
- Divide time into fixed intervals and maintain a counter for each interval.
- Reject requests after the configured limit is reached.
- Counters must be coordinated when multiple service instances enforce the same limit.
- Window boundaries can allow bursts across two adjacent windows.
- The algorithm is simple and inexpensive but provides less even traffic shaping than sliding-window approaches.
Interview questions
Why can a naive in-memory implementation fail in a concurrent Java service?
Two requests can read the same counter value before either request updates it, causing lost increments. That can make the limiter accept more requests than intended. The implementation therefore needs a concurrency-safe operation, such as an atomic counter or suitable synchronization. In a multi-instance deployment, thread safety alone is not enough because each instance would otherwise maintain a separate limit.
How does a fixed window rate limiter work?
The limiter divides time into fixed intervals and keeps a request count for the current interval. Each accepted request increments that count. Once the count reaches the configured limit, further requests are rejected until the next window begins. At the boundary, the counter starts again for the new interval.
What is the main weakness of a fixed window limiter?
Its main weakness is the boundary burst. A client can use nearly the entire quota at the end of one window and then nearly the entire quota again immediately after the next window starts. Therefore, the observed short-term request rate can be much higher than the nominal limit suggests.
How would you implement a fixed window limiter in a Java backend?
I would associate a counter with a limiting key such as an API key or user ID and a window identifier. For a single-instance service, this could be held in memory with appropriate concurrency control. For multiple instances, I would use shared storage such as Redis and make the increment-and-limit operation atomic. I would also define behavior for storage failures and decide whether rejected requests return HTTP 429.
How would you choose between fixed window and a sliding-window limiter?
I would start with the required traffic behavior rather than choosing based only on implementation simplicity. Fixed windows are straightforward and inexpensive when occasional boundary bursts are acceptable. A sliding-window design is more appropriate when the limit should better represent traffic over a continuously moving period. The choice also depends on storage cost, implementation complexity, latency requirements, and whether the limiter is distributed.