Implement a Per-IP Sliding Window Rate Limiter
RampSoftware Engineer · Technical ScreenLast updated
Implement a per-IP sliding window rate limiter that tracks request timestamps to enforce rate limits over a rolling time window. The problem evaluates state management, time-window data structures, memory leak prevention, and edge-case handling.
Problem Statement
Design and implement an in-memory, per-IP rate limiter using the sliding window log strategy. The rate limiter must ensure that no single IP address can exceed a specified number of requests (limit) within any rolling time duration (window_size in seconds).
You need to implement the SlidingWindowRateLimiter class with the following methods:
__init__(self, limit: int, window_size: int): Initializes the rate limiter with the allowed requestlimitand the slidingwindow_sizein seconds.allow_request(self, ip: str, timestamp: int) -> bool: Determines whether a request from the givenipat Unix timestamptimestamp(in seconds) should be accepted. If accepted, record the request and returnTrue. If rejected, do not record the request and returnFalse.
A request is allowed if the number of accepted requests from that IP in the half-open interval (timestamp - window_size, timestamp] is strictly less than limit.
Class Interface
class SlidingWindowRateLimiter:
def __init__(self, limit: int, window_size: int):
"""
Initialize rate limiter with capacity limit and window size in seconds.
"""
pass
def allow_request(self, ip: str, timestamp: int) -> bool:
"""
Check and record if request from IP at timestamp should be allowed.
"""
pass
Example
limiter = SlidingWindowRateLimiter(limit=3, window_size=10)
# All requests for IP "10.0.0.1"
limiter.allow_request("10.0.0.1", 1) # -> True (count in (1-10, 1] is 1)
limiter.allow_request("10.0.0.1", 2) # -> True (count in (2-10, 2] is 2)
limiter.allow_request("10.0.0.1", 5) # -> True (count in (5-10, 5] is 3)
limiter.allow_request("10.0.0.1", 8) # -> False (limit reached, 3 requests in (0, 8])
limiter.allow_request("10.0.0.1", 11) # -> True (request at t=1 fell out of (1, 11]; count becomes 3)
# Independent IP
limiter.allow_request("10.0.0.2", 8) # -> True (new IP, count is 1)
Constraints
1 = 0- Within calls for a given IP,
timestampvalues are provided in non-decreasing order. - Total calls to
allow_request: up to10^6.
Edge Cases
- Multiple requests occurring at the exact same second.
- Boundary condition: a timestamp occurring exactly at
timestamp - window_sizemust be expired. - Inactive IP addresses should not accumulate memory indefinitely if their entries become empty.
Hints
Hint 1
Use a double-ended queue (deque) per IP to store the timestamps of accepted requests.
Hint 2
When a request arrives at time t, evict timestamps from the front of the queue that are less than or equal to t - window_size before checking the limit.
Hint 3
If the queue becomes empty after eviction or an IP is inactive, consider removing the key from your hash map to prevent unbounded memory growth.
Follow-up questions
- How would you ensure thread-safety if multiple threads call `allow_request` concurrently across distinct or identical IPs?
- If the volume of requests per IP is extremely high, storing individual timestamps can exhaust memory. How would you trade off precision using a sliding window counter algorithm?
- How would you scale this rate limiter in a distributed architecture where requests hit multiple API gateway instances behind a load balancer?
Solution walkthrough is for members
Get the full walkthrough with reference code and complexity analysis, plus Kitty Coach at 300 messages a day. Hints, the code runner and community answers stay free.