Rate Limiting with Redis
In this lesson, you will learn how to maintain a consistent rate-limiting policy across multiple server instances by offloading your throttling state to a centralized Redis cache.
The Problem with Local State
When you run a Node.js application in a cluster (as we discussed in our "Clustering Multiple Workers" module), you likely use an in-memory object to keep track of request counts per IP address. This works fine for a single process, but it fails in a distributed environment. If an incoming request hits Worker A, it has no idea how many requests that same user sent to Worker B. Consequently, a user could bypass your limits simply by hitting different instances of your server.
Centralizing the Throttle
To fix this, we move the "count" and the "expiration timer" out of the local memory and into Redis. Because Redis acts as a shared, high-speed data store, every server instance connects to the same source of truth.
When a request arrives, the middleware performs an atomic "increment and expire" operation in Redis. Here is the logic:
// Simplified middleware flow
async function rateLimit(req, res, next) {
const userKey = `rate_limit:${req.ip}`;
// Increment the request count in Redis
const count = await redis.incr(userKey);
// Set expiration if it's the first request
if (count === 1) {
await redis.expire(userKey, 60); // 1 minute window
}
if (count > 100) {
return res.status(429).send("Too Many Requests");
}
next();
}
Why this scales
By using Redis, your rate-limiting state is decoupled from your application logic. Even if you spin up ten new server instances to handle a spike in traffic, they all verify the request count against the same centralized data. This ensures your API stays protected, regardless of how many workers are active or which server picks up the next request. This architecture keeps your "Request Sanitization" and "Feature Toggling" layers consistent across your entire infrastructure.
Key Takeaway: By offloading throttle counters to Redis, you ensure that rate limits are enforced globally across your entire server cluster rather than being siloed within individual worker instances.