Rate Limiter using Redis
Rate limiting is a common technique used to control the rate of incoming requests or operations from a client. Redis, an in-memory data structure store, can be used effectively for implementing rate limiting due to its fast response times and support for atomic operations.
There are several approaches you can take to implement rate limiting using Redis. Here's one common method:
It's important to note that implementing rate limiting solely with Redis may not be sufficient in all scenarios. In distributed systems or high-throughput environments, you may need additional mechanisms, such as a distributed cache or a distributed key-value store, to ensure accurate rate limiting across multiple instances or nodes.
Recommended by LinkedIn
Remember to consider the specific requirements and characteristics of your application when designing and implementing rate limiting using Redis.
Concept in action :
import time
import redis
class RateLimiter:
def __init__(self, redis_host, redis_port, max_requests, time_window):
self.redis_client = redis.Redis(host=redis_host, port=redis_port)
self.max_requests = max_requests
self.time_window = time_window
def is_request_allowed(self, identifier):
current_time = int(time.time())
# Remove expired entries from the sorted set
self.redis_client.zremrangebyscore(identifier, 0, current_time - self.time_window)
# Get the count of requests within the time window
request_count = self.redis_client.zcard(identifier)
if request_count >= self.max_requests:
return False
# Add current timestamp to the sorted set
self.redis_client.zadd(identifier, {current_time: current_time})
# Set expiration time for the sorted set
self.redis_client.expire(identifier, self.time_window)
return True
# Example usage
redis_host = 'localhost'
redis_port = 6379
max_requests = 100
time_window = 60 # 60 seconds
limiter = RateLimiter(redis_host, redis_port, max_requests, time_window)
# Simulating multiple requests
for i in range(110):
identifier = 'user123' # Replace with your identifier (e.g., user ID or IP address)
if limiter.is_request_allowed(identifier):
print(f"Request {i+1} allowed")
else:
print(f"Request {i+1} rejected")
time.sleep(1) # Sleep for 1 second between requests
I think the order of operations to make it work should be 1 zadd 2 zremrangebyscore 3 zcard 4 check threshold
If you are already trimming the older entries from the SortedSet with zremrangebyscore call, then why do you need to expire the whole SortedSet data structure?
The logic wouldn't work when there are multiple requests at the same timestamp.