DRL(distributed rate limiter)

Requirements
High Level Design
Block Diagram
Request Flow
Flow Diagram
Rate Limiter System Design(github)

Algorithms

Fixed Window Counter

Multithreaded Code
Divide time into fixed windows (e.g., 00:00–00:59, 01:00–01:59). Maintain a counter per window. When a request arrives, increment the counter. If the counter exceeds the limit, reject the request. The counter resets at the window boundary.

 
// 10 req/min
Window 1 (12:00 - 12:01)         Window 2 (12:01 - 12:02)
  |-------10 req-------|         |-------10 req--------|
   |  |  |  |   |                 
               drop
        

Sliding Window

Maintain the sliding window (let suppose 60 seconds). And fixed tokens are allowed in this window.
Sliding window counts only requests within the last N seconds by remembering when each request arrived. It never resets abruptly at a fixed boundary.


Last 60 seconds at 12:01:05: 80 requests
        

Sliding Window Counter (Approximate Sliding Window)

Approximate sliding window combines two adjacent fixed windows and weights them to approximate the true moving interval.


Window A (11:00 - 11:01): 60 req
Window B (11:01 - 11:02): 30 req
Weighted count ≈ 15 + 30 = 45 requests
        

Leaky bucket

Leaky bucket releases requests at a steady pace. Incoming requests may queue briefly, but the output rate stays smooth.


Bucket leaks 1 request/sec
Burst of 10 requests → 1 allowed each second until the burst is drained
        

Token bucket

Each request consumes one token — if none remain, deny immediately. That matches how clients and gateways behave.
Runs inside atomic Lua script on Redis.


Bucket capacity 10, refill 1 token/sec
Start with 10 tokens. A burst of 10 is allowed immediately, then 1 more
request per second as tokens refill.
        


# Token bucket state (per rule + subject key)
bucket:{rule_id}:{subject} → {
  tokens: FLOAT,
  last_refill: TIMESTAMP
}

function allow_request(bucket, now, rate, capacity):
  elapsed = now - bucket.last_refill
  refill = elapsed * rate
  bucket.tokens = min(capacity, bucket.tokens + refill)
  bucket.last_refill = now

  if bucket.tokens >= 1:
    bucket.tokens -= 1
    return allowed, bucket.tokens
  else:
    return denied, 0

# Example:
# capacity=10, rate=1 token/sec
# start with 10 tokens → 10 requests allowed immediately
# then 1 request allowed per second as tokens refill