Designing a rate limiter for a distributed system can be challenging due to requirements such as scalability, fault-tolerance, and synchronization. Several methods can be used depending on the context and use cases. Here we discuss three common concepts used in designing rate limiters.
1. **Fixed Window Algorithm:**
The fixed window algorithm divides the time into equal size windows and allows only certain number of requests per window. If the limit is exceeded, subsequent requests are blocked until the next window.
Counter algorithm pseudocode:
If RequestTime > WindowEnd
RequestCount = 1
WindowEnd = RequestTime + WindowSize
Else
If RequestCount > RateLimit
Block Request
Else
RequestCount++
But it has a problem called burst traffic due to the synchronized requests after each window.
2. **Sliding Window Log Algorithm:**
Sliding window log algorithm solves the problem in the fixed window by logging each request’s timestamp. It ensures that the count of requests within any given window size does not exceed the limit. But it requires large storage to save logs individually.
Sliding log pseudocode:
Log[RequestTime] = Request
Remove logs older than WindowSize from Log[RequestTime]
If Sizeof(Log) > RateLimit
Block Request
3. **Token Bucket Algorithm:**
In this algorithm, a token is added to the bucket at every 1/rate time interval until it hits the capacity. When a request comes in, a token is removed if possible. If not, the request is blocked/waited until next token comes in.
Token bucket pseudocode:
At every 1/rate interval, Do
If TokenCount < Capacity
TokenCount++
Every Request, Do
If TokenCount > 0
TokenCount--
Else
Block/Wait the Request
In a distributed system, these algorithms need to be modified slightly due to concurrency issues. For example:
- A global counter/token-bucket can be implemented using a distributed lock to prevent race conditions.
- It can also be implemented locally on every machine and use a consensus protocol for synchronization. But the real-time hard limit cannot be guaranteed.
- Distributed logging system like Apache Kafka can be used for Sliding Window Log algorithm where timestamps are saved into the log in a distributed and fault-tolerant manner.
Use of a centralized key-value database store (for example, Redis) can also provide a solution. Two scenarios where Redis can be used efficiently:
- With Redis, you can model fixed window rate limiter using simple Redis commands combined with Lua script to make the operation atomic.
- For the sliding window rate limiter, the Sorted Sets data structure in Redis can be used.
Overall, each method has its advantages and trade-offs. It is essential to understand the behavior of incoming request traffic, system capacity, and specific needs of the application that integrates this rate limiter to choose a suitable method.