Katkat

Implement a Leaky Bucket Limiter

SnapchatSoftware Engineer · Onsite

Last updated

This problem tests your ability to implement a thread-safe rate limiter using the Leaky Bucket algorithm, requiring careful management of timestamps and shared state.

Problem Statement

Implement a LeakyBucket class that regulates traffic based on a fixed capacity and a constant leak rate. The bucket holds a maximum of capacity tokens. Tokens are added to the bucket periodically (the 'leak' process), effectively limiting the number of requests allowed within a time window.

API Design

Implement the following methods:

  • __init__(self, capacity: int, leak_rate_per_second: float): Initializes the bucket. capacity is the maximum number of requests allowed in the burst. leak_rate_per_second is how many requests can be processed per second.
  • allow_request(self) -> bool: Returns True if a request can be processed (if a token is available), otherwise returns False.

Requirements

  • The implementation must be thread-safe.
  • Use time.time() to track the passage of time.
  • Ensure the bucket state is updated lazily (i.e., calculate the number of leaked tokens only when a request arrives).

Examples

# Capacity 3, Leak rate 1.0 request per second
bucket = LeakyBucket(3, 1.0)

bucket.allow_request() # Returns True (Current bucket: 2)
bucket.allow_request() # Returns True (Current bucket: 1)
bucket.allow_request() # Returns True (Current bucket: 0)
bucket.allow_request() # Returns False

# Wait 2 seconds
# Bucket now has 2 tokens (1 per second)
bucket.allow_request() # Returns True

Constraints

  • capacity > 0
  • leak_rate_per_second > 0
  • Handle high-concurrency environments using locks.

Edge Cases

  • Requesting at the exact millisecond a token is generated.
  • Multiple threads calling allow_request() simultaneously.
  • Very high throughput exceeding the capacity significantly.

Hints

Hint 1

Instead of running a background thread, calculate the number of tokens leaked since the last request based on the elapsed time.

Hint 2

Use a timestamp variable to store when the bucket was last updated and update this timestamp only when `allow_request` is invoked.

Hint 3

Wrap the state updates (timestamp and current token count) inside a mutual exclusion lock to ensure atomicity in a multi-threaded environment.

Follow-up questions

  • How would you modify this implementation to support distributed rate limiting across multiple server instances?
  • What are the trade-offs between the Leaky Bucket algorithm and the Token Bucket algorithm in terms of traffic shaping?
  • If the 'leak rate' changed dynamically based on server load, how would you adjust the logic to prevent race conditions during updates?