Redis Hot Keys: Fixing Latency Spikes at Scale
A Redis hot key problem silently overloads one shard and spikes p99 latency for everyone. Here's how to detect it, fix it, and architect around it before it takes down production.
A Redis hot key problem silently overloads one shard and spikes p99 latency for everyone. Here's how to detect it, fix it, and architect around it before it takes down production.
If you searched for "redis hot key problem" or "why does my redis latency spike under load," here's the short answer up front: a hot key is a single key receiving a disproportionate share of traffic, and it can pin the CPU of one shard while the rest of your cluster sits idle. You can't eliminate hot keys by adding more nodes — you fix them by detecting the pattern, splitting or caching the key client-side, and coalescing duplicate requests so one popular row doesn't become a single point of failure for your whole SaaS.
Hot keys are one of the most misdiagnosed production incidents in Redis-backed systems. The metrics look like a capacity problem — CPU, memory, and connection counts all look fine on average — but p99 latency climbs, timeouts appear in one region, and nobody can explain why scaling the cluster horizontally didn't help. This is the last piece in our Redis-at-scale series, following our deep dives into RDB vs AOF persistence trade-offs and maxmemory eviction policy. Here we cover the failure mode neither of those fixes: uneven key-level load.
Redis Cluster and most managed Redis offerings (ElastiCache, MemoryDB, Redis Cloud) shard data across nodes using a hash slot. In theory this spreads load evenly. In practice, real-world access patterns are almost never uniform — they follow a power law. A viral product listing, a trending hashtag, a single tenant's dashboard config, a global rate-limit counter, or a feature flag checked on every request can all funnel a huge share of traffic onto one key, and therefore one shard.
Because Redis is single-threaded for command execution (even Redis 7+'s I/O threading doesn't parallelize command processing on one key), every GET, INCR, or HGETALL against that key serializes behind the others. Adding shards doesn't help, because the hot key still lives on exactly one shard — you've just added capacity nothing was using. This is the core reason "scale out" and "fix the hot key" are two separate problems.
You need visibility at the key level, not just the instance level. In our client engagements, we layer three detection methods so no single blind spot hides an emerging hot key:
Avoid running MONITOR in production to hunt for hot keys — it captures every command and can itself become a bottleneck on a busy instance. Treat it as a last-resort, time-boxed diagnostic tool, never a standing dashboard.
For counters and aggregates (view counts, rate limiters, leaderboard scores), shard the key itself: write to key:{id}:{0-9} chosen by a hash of the client or request, then sum the shards on read. This turns one hot key into ten warm ones distributed across the cluster. It's the single highest-leverage fix for INCR-heavy hot keys and requires no infrastructure change.
If the same handful of keys — a feature-flag set, a pricing table, a tenant's config — are read on nearly every request, cache them in-process (an LRU map in your app, or a library like node-lru-cache) with a short TTL of 1-5 seconds. This is the caching-strategy lever most teams skip: at high throughput, shaving even a few hundred milliseconds of local freshness off a handful of hot reads removes 90%+ of the Redis calls for those keys entirely, because most SaaS config and flag data doesn't need per-request freshness.
When a hot key expires, a cache stampede sends dozens or thousands of concurrent requests to the database to regenerate the same value simultaneously. Wrap cache misses in a single-flight pattern (one in-flight regeneration per key, other callers await the same promise) or take a short SET NX lock before recomputing. Combine this with TTL jitter — add ±10-20% random variance to expirations — so keys set at the same time don't all expire in the same millisecond.
For read-heavy hot keys where slight staleness is acceptable, route reads to replicas (READONLY mode in Cluster, or explicit replica endpoints) instead of the primary. This doesn't fix an imbalanced shard, but it multiplies the read capacity available for that specific key across N replicas, buying time while you implement a structural fix.
| Symptom | Likely cause | Fix |
|---|---|---|
| One shard's CPU is pegged, others idle | Single hot key on that shard | Client-side key splitting |
| Latency spikes right after a cache expiry | Cache stampede on a popular key | Single-flight + TTL jitter |
| Config/flag reads dominate command count | Read-heavy hot key, no local cache | L1 in-process cache with short TTL |
| Spikes correlate with a specific tenant or region | Tenant-level hot key (noisy neighbor) | Per-tenant key namespacing + rate limits |
| Replication lag grows during traffic peaks | Primary saturated by hot writes | Write batching or key sharding on the counter |
“A hot key incident almost never shows up as 'Redis is slow.' It shows up as one customer, one feature, or one region having a bad day while every dashboard you're staring at looks average. You have to go looking for it at the key level — the aggregate metrics will lie to you.”
A common pattern we see in SaaS and e-commerce platforms: a single Redis key caches a global pricing or promotion config, read on every page load and every checkout call. Traffic is fine at normal volume. Then a promotion goes out in an email blast or gets picked up by a deal aggregator, request volume triples in minutes, and that one key's shard maxes out its CPU while every other shard in the cluster sits under 20% load. Checkout latency climbs, timeouts cascade into the payment provider's retry logic, and the team scales the Redis cluster horizontally — which does nothing, because the new nodes never see a single request for that key.
The actual fix took under a day: move the pricing config to an in-process cache refreshed every 2 seconds via Redis pub/sub invalidation, so 99% of reads never hit Redis at all, and the remaining refresh traffic is naturally staggered. This is the kind of architectural review we run for clients before a launch or campaign that we expect to spike traffic — cheaper to find in a load test than in a postmortem.
We build and operate Redis as caching, session, and queue infrastructure for SaaS platforms running on Laravel, Node.js, and TypeScript stacks, deployed on AWS (ElastiCache and self-managed clusters alike). Hot-key and eviction-policy reviews are a standard part of our pre-launch and pre-scale-event checklists — the same checklist we use before a client's product launch, funding announcement, or seasonal traffic spike — so the failure mode above gets caught in staging, not in your incident channel.
A hot key is any single key that receives a disproportionately large share of read or write traffic compared to the rest of your keyspace. Because Redis Cluster shards by key, one hot key concentrates load on a single shard, and that shard's single-threaded command execution becomes a bottleneck regardless of how many other nodes are in the cluster.
A big key is large in size (a huge hash, set, or list), which slows down individual commands and can block the event loop during operations like DEL or expiration. A hot key is small but accessed extremely frequently. The two can compound — a large, frequently-read key is often the worst-case combination — but they need different fixes: big keys need restructuring or TTL-based cleanup, hot keys need traffic distribution or local caching.
No. Redis Cluster distributes different keys across shards using hash slots, but it cannot split a single key's traffic across multiple nodes. If one key is hot, it stays on one shard no matter how many nodes you add. Cluster helps with overall dataset and throughput scaling, not with an individual key's popularity.
Use a single-flight pattern so only one request regenerates the value while concurrent callers wait for that result instead of all hitting the database, and add TTL jitter (±10-20% random variance) so keys set together don't expire in the same instant. A short SET NX lock around the regeneration step accomplishes the same goal if your stack doesn't have an in-process single-flight library available.
Yes — session data is naturally well-distributed because each session has its own key, which is the opposite of a hot-key access pattern. The risk case is different: a shared session-adjacent key (a global config or rate-limit counter checked alongside every session lookup) is what tends to go hot, not the sessions themselves.
Want a second pair of eyes on your Redis scaling strategy? Read our companion guide on scaling Redis for high-traffic SaaS to see the full picture, from sharding to failover.
Read: Scaling Redis for High-Traffic SaaSPlanning a launch or traffic spike and want your caching layer stress-tested before it happens in production?
Talk to Fepiq about your Redis architectureOccasional, no-fluff notes on shipping modern software — startups, automation, Laravel, Shopify and more. No spam, unsubscribe anytime.
Keep reading
What is an index in SQL? A plain-English guide with copy-paste examples showing how indexes speed up queries and when you actually need one.
Learn JavaScript DOM manipulation for beginners: select elements, change text and styles, and handle clicks with simple, copy-paste code examples.
Let's build something
Book a free discovery call. We'll listen, ask sharp questions, and send you a proposal within 3 business days.