Time is cut into windows of equal length, each with a counter. A request is counted and let through while the counter is under the limit, and refused after that until the counter resets to zero at the next boundary. Below, an attacker joins two ordinary users: watch who is refused when they share one counter and when each has their own, and what happens when the attacker times bursts around a boundary.
Each dot stands for 579 real requests. Time is not scaled. The busiest stretch counts what got through in any 5 seconds in a row, not only in the windows as the counter sees them. That is how the boundary problem shows up.
Busiest hour vs the daily average. The book's estimate uses 2x.
Real limits often use a minute or an hour; the animation stays short so you can watch windows go by.
1. Average requests per second
2. Peak requests per second
3. Allowed rate r
4. Limit per window L
5. What is arriving right now
Doubling DAU doubles the traffic, and because r and L are sized from that same traffic, it doubles them too. Every ratio stays the same, so the counter behaves identically and only the number each dot stands for changes. What changes the behaviour is traffic relative to r: the peak factor and the attack. The window length changes how long each refused stretch lasts.
Steps 1 and 2 are the estimation method from the back-of-the-envelope chapter of Alex Xu's System Design Interview, Vol. 1, including its 2x peak. A window length and a limit per window are the fixed window counter's two parameters in its rate limiter chapter, which also points out the boundary weakness shown here. The book does not give a single formula joining the two; steps 3 to 5 are that join, written here. The 2L bound follows from the reset: each of two neighbouring windows may let through L.
One shows how to build a fixed window counter, the other how a large API reports a windowed limit to clients.
INCR command includes a rate limiter pattern built exactly this way. The key is the client's IP address joined to the current Unix time in seconds, so every second starts a new key, and with it a new count. Each request runs INCR on that key and sets EXPIRE to 10 seconds so old keys clean themselves up; if the count is over 10, the request is refused with an error. That is a per-IP counter with a one-second window and a limit of 10. Putting the window in the key means there is nothing to reset: the next second simply uses a different key.x-ratelimit-reset header is documented as "The time at which the current rate limit window resets in UTC epoch seconds." That is how GitHub reports its limit to clients; the documentation does not describe how it is counted internally, so read it as the client's view of a windowed limit, not as GitHub's implementation.Both are the projects' own documentation (primary sources). The quoted sentence is a short attributed quotation; the Redis pattern is described in our words. Limits change, so check the pages for current values.