Sliding-Window Rate Limiter
A model API limits every API key in two ways at once: a number of requests and a number of tokens in any rolling window of window seconds. Two limits matter because a few huge prompts can cost more GPU time than thousands of tiny ones.
Requests arrive in time order. Request i comes at second times[i] from key keys[i] and asks for tokens[i] tokens. When it arrives at second t, look at the requests from the same key that were accepted in the window (t - window, t], that is, strictly after t - window. The new request is accepted when, counting it too:
- the number of accepted requests in the window is at most
maxRequests, and - their tokens add up to at most
maxTokens.
Otherwise it is refused, and a refused request does not count towards anything later. Each key has its own limits; keys do not affect each other.
Return, for every request, whether it was accepted.
Example
window = 60, maxRequests = 3, maxTokens = 1000. Key 1 sends 400 tokens at second 0 and 400 at 10 (both accepted). At 20 it asks for 300, which would make 1,100 tokens: refused. At 30, 200 tokens make exactly 1,000: accepted. Key 2 is unaffected at 40. At 50, key 1 would make a fourth request: refused. At 60 the request from second 0 has left the window (it is not after 60 - 60 = 0), leaving 600 tokens in 2 requests, so 100 more is accepted. At 61 the window holds the requests from 10, 30 and 60, already three: refused.
The answer is [true, true, false, true, true, false, true, false].
[ "60", "3", "1000", "[0,10,20,30,40,50,60,61]", "[1,1,1,1,2,1,1,1]", "[400,400,300,200,900,1,100,400]" ]
Explanation. The example.
[ "10", "1", "100", "[0,10,19,20]", "[0,0,0,0]", "[50,50,50,50]" ]
Explanation. A request exactly `window` seconds old no longer counts.
[ "5", "10", "100", "[1,2]", "[3,3]", "[101,100]" ]
Explanation. A request larger than the token limit is always refused.
[ "100", "2", "1000", "[0,1,2,3,100,101]", "[7,7,7,7,7,7]", "[1,1,1,1,1,1]" ]
Explanation. Refused requests use up nothing.
[ "30", "2", "50", "[0,0,5,5,6,31,31]", "[1,2,1,2,1,1,2]", "[30,30,20,25,1,10,25]" ]
Explanation. Keys are limited separately.
[ "1", "2", "10", "[5,5,5,6]", "[0,0,0,0]", "[3,3,3,3]" ]
Explanation. Several requests in the same second.
[ "1000000", "100000", "2000000", "[0,999999,1000000,1000001]", "[999999999,999999999,999999999,999999999]", "[1000000,1000000,1000000,1]" ]
Explanation. Large values: the request from second 0 leaves the window exactly at second 1,000,000.
Follow-up: The limiter now runs on 50 API servers behind a load balancer, and a key's requests land on any of them. What happens to your exact window, and what would you trade for keeping the limits approximately right without a database round trip per request?
- `1 <= window <= 10^6` - `1 <= maxRequests <= 10^5` - `1 <= maxTokens <= 10^9` - `1 <= times.length <= 10^5`, and `times`, `keys` and `tokens` have the same length. - `0 <= times[i] <= 10^9`, and `times` is non-decreasing. - `0 <= keys[i] <= 10^9` - `1 <= tokens[i] <= 10^6`
- Views
- 2