How To

Redis Monitoring: 6 Metrics That Decide If Your Cache Is Helping

Redis fails gradually and then suddenly. The six metrics that decide whether your cache is helping, what bad looks like for each, the redis-cli check that finds it, and how to read a latency spike by ruling out causes in order.

10 min read
Cover Image for Redis Monitoring: 6 Metrics That Decide If Your Cache Is Helping

Redis Monitoring: 6 Metrics That Decide If Your Cache Is Helping

Most stacks have a Redis instance that started life as "just a cache." Then someone stored sessions in it. Then rate-limit counters, then a job queue, then a leaderboard. Nobody declared a migration, but at some point it stopped being a cache and became a primary datastore: one with no schema, no query planner and, in most shops, no real monitoring beyond "the pod is green."

That's why Redis monitoring is a different problem from checking that a pod is up. Redis fails gradually and then suddenly. Hit ratio erodes for weeks, fragmentation creeps up, and the visible incident (a latency spike, an eviction storm, an out-of-memory error at peak traffic) is only the last frame of the film. Monitoring Redis well means watching six specific signals, knowing what "bad" looks like for each, and having one command ready to check it. Every check in this guide runs from redis-cli in seconds.

Part two is a hands-on Redis performance audit using only native tools. Part three covers automating continuous Redis monitoring with an AI agent.

01Effectiveness

Hit ratio

The share of reads Redis answers. Every lost point is load moved to the database.

02Memory

Fragmentation

RSS against used memory. RAM you pay for that holds nothing.

03Memory

Evictions

What Redis does at maxmemory: fail writes, or delete keys you may need.

04Latency

Slow commands

One O(N) command on a single thread stalls every connected client.

05Latency

Big and hot keys

One huge value or one popular key caps what the whole node can do.

06Durability

Replication lag

Stale reads now, lost writes at the next failover.

The six metrics this guide covers, each with a redis-cli check that runs in seconds.

Why "the pod is green" misses all six

The default Redis health check is a PING and a memory graph. Both stay healthy right up to the incident, for three structural reasons:

  • The counters are cumulative. keyspace_hits, evicted_keys and friends count since the last restart. On an instance that's been up for 90 days, a hit ratio that collapsed this week barely moves the lifetime number.
  • The memory graph shows the wrong memory. Most dashboards plot used_memory. Fragmentation lives in the gap between that and RSS, which is what actually gets your node OOM-killed.
  • One thread hides the cause. Redis runs commands on a single thread, so one slow command shows up as a latency spike on every client. The graph tells you something was slow. It doesn't tell you what.

The six checks below look past all three.


1. Cache hit ratio

What it is. The share of reads Redis answers from memory instead of returning a miss that your application then serves from the database. Redis doesn't report it directly. You compute it from two counters in INFO stats:

redis-cli INFO stats | grep -E 'keyspace_hits|keyspace_misses'

Hit ratio = keyspace_hits / (keyspace_hits + keyspace_misses). These counters are cumulative since the last restart, so for a live picture, sample twice a few minutes apart and diff.

What bad looks like. For a true cache workload, a sustained ratio below roughly 90% deserves a look, and below 80% something is structurally wrong: TTLs shorter than the reuse interval, cache keys that include a timestamp or UUID so they never repeat, or a working set larger than maxmemory so useful keys get evicted before they're read again.

Typical impact. Every point of hit ratio you lose is load moved to the database behind Redis. Dropping from 95% to 85% triples the miss traffic. The database sees three times the cache-miss queries, and p99 on those requests goes from sub-millisecond to whatever your database does under pressure.

2. Memory fragmentation ratio

What it is. mem_fragmentation_ratio in INFO memory is the ratio between the memory the OS has given the Redis process (RSS) and the memory Redis thinks it's using (used_memory). Churn-heavy workloads (lots of writes, deletes and varying value sizes) leave the allocator holding pages it can't return.

redis-cli INFO memory | grep -E 'used_memory_human|used_memory_rss_human|mem_fragmentation_ratio'

What bad looks like. Between 1.0 and about 1.4 is healthy. Above 1.5, a meaningful share of your RAM is allocator overhead; at 2.0, a "4 GB" Redis occupies 8 GB of real memory. Below 1.0 is bad news of a different kind: the OS has swapped part of Redis to disk, and any command touching a swapped page stalls the whole single-threaded event loop. (On a very small dataset the ratio is noisy and can read high for harmless reasons. Judge it on instances with at least a few hundred MB of data.)

Typical impact. Fragmentation is invisible until capacity math fails: the instance OOMs or starts evicting while used_memory still looks fine. On managed platforms it often forces a node-size upgrade one tier early, so you pay for RAM the allocator wastes. Modern Redis can defragment live with activedefrag yes, and redis-cli MEMORY DOCTOR gives the allocator's own diagnosis.

3. Evictions and expirations under maxmemory

What it is. When Redis reaches maxmemory, the configured maxmemory-policy decides what happens. noeviction makes writes fail with an OOM error; the allkeys-* and volatile-* policies delete keys to make room. Watch the counters:

redis-cli INFO stats | grep -E 'evicted_keys|expired_keys'
redis-cli CONFIG GET maxmemory-policy

What bad looks like. Two failure modes with opposite symptoms. With noeviction (the default in open-source Redis), a full instance starts returning OOM command not allowed when used memory > 'maxmemory', which is an outage for anything that writes. With an allkeys-* policy, a full instance keeps working while deleting data. That's fine for pure cache entries and a disaster when the same instance also holds sessions or queue items, because "cache eviction" becomes "users randomly logged out." A steadily climbing evicted_keys means the working set no longer fits. A near-zero expired_keys on a cache workload means keys have no TTLs at all and only eviction pressure ever removes them.

01Weeks before

Keys without TTL

The keyspace grows and only eviction pressure ever removes anything.

02Peak traffic

maxmemory hit

Evictions start, or writes fail if the policy is noeviction.

03Minutes later

Hit ratio drops

Useful keys are gone. Misses fall through to the database.

04Same hour

Database saturates

Recompute and rewrite trigger more evictions. The loop feeds itself.

Metrics 1 and 3 are one incident. The cheap moment to fix it is the first cell, weeks earlier.

Typical impact. Eviction storms feed themselves: evictions lower the hit ratio, misses trigger recomputation and rewrites, and the rewrites trigger more evictions. Teams usually discover the mixed-workload problem during their first big traffic spike, as a wave of support tickets rather than a metric.

4. Slow commands: KEYS and the O(N) family

What it is. Redis executes commands on a single thread. One KEYS * against a few million keys, an HGETALL on a giant hash, SMEMBERS on a huge set or LRANGE mylist 0 -1 blocks every other client until it finishes. The slow log records anything over slowlog-log-slower-than (default 10,000 microseconds):

redis-cli SLOWLOG GET 10

For intermittent stalls that aren't slow commands (forks for persistence, transparent huge pages, disk I/O), enable latency monitoring with CONFIG SET latency-monitor-threshold 100 and ask Redis to diagnose itself with LATENCY DOCTOR.

What bad looks like. Any KEYS in the slow log of a production instance (use SCAN, always). Repeated entries for the same command pattern at 50 ms and up. And a slow log that's empty not because the instance is healthy but because it only keeps the last 128 entries by default and nobody reads it.

Typical impact. A single 200 ms command is a 200 ms latency spike for every client connected at that moment. It's the most common source of mysterious p99 spikes that "don't correlate with anything" on the CPU or network graphs.

5. Big keys and hot keys

What it is. Two different concentration problems. A big key is one enormous value (a 500 MB hash, a list with two million entries) that makes every operation touching it expensive, and makes deleting or evicting it a stall event. A hot key is a small key that gets a disproportionate share of traffic, pinning one shard or one CPU core while the rest of the cluster idles. Find them with the built-in scanners:

redis-cli --bigkeys
redis-cli --hotkeys   # needs an LFU maxmemory-policy (allkeys-lfu or volatile-lfu)

Both use incremental SCAN under the hood, so they're safe for production, if not free. For a specific suspect, redis-cli MEMORY USAGE keyname reports its exact size in bytes.

What bad looks like. Any single key holding more than a few MB, or a collection with hundreds of thousands of elements. For hot keys, one key taking an order of magnitude more operations than its peers. The classic case is a shared counter or a "front page" cache entry that every request reads.

Typical impact. Big keys turn routine operations into incidents. A DEL on a multi-GB key can block for seconds (use UNLINK, which frees memory in the background). Hot keys cap your cluster's throughput at the capacity of one node, which is why "we sharded Redis and nothing got faster" is such a common story.

6. Replication lag

What it is. If you run replicas for read scaling or failover, each replica applies the primary's write stream asynchronously. The gap is measured in bytes of replication offset:

redis-cli INFO replication

On the primary, compare master_repl_offset with the offset in each slaveN: line. The difference is the lag. On the replica, also check master_link_status:up.

What bad looks like. An offset gap that grows instead of hovering near zero, or repeated full resynchronizations (sync_full climbing in INFO stats). That's usually a sign the replication backlog (repl-backlog-size, default 1 MB) is too small for your write rate, so every brief network blip forces a full copy of the dataset.

Typical impact. Stale reads: a user writes on the primary and reads their old data back from a lagging replica. Worse, a failover to a lagging replica loses every write inside the gap, silently. Repeated full syncs also hammer the primary, since each one forks the process and snapshots the dataset.


Reading a latency spike: one worked example

The checks pay off when you run them against one symptom in order. Say p99 on your API jumped from 4 ms to 180 ms at 21:00 and recovered by 21:20. Four readings fit, and each predicts something different:

  1. A slow command. The slow log has entries clustered around 21:00, probably one repeated pattern.
  2. A fork. LATENCY LATEST shows a fork event near 21:00, lined up with an RDB save or a replica full sync (sync_full went up).
  3. Eviction pressure. evicted_keys jumped in the same window and hit ratio dropped, so the latency is really database latency on misses.
  4. Swap. mem_fragmentation_ratio is below 1.0 and the OS reports swap in use.

Check them in that order. If SLOWLOG GET 25 shows forty HGETALL session:* entries at 120 to 200 ms each, you have your answer, and MEMORY USAGE on one of those keys will tell you how big the hash grew. If the slow log is clean but LATENCY HISTORY fork has a 900 ms spike at 21:00:04, look at the persistence schedule instead. The point is that each reading leaves a different fingerprint, and you can rule three of them out in a few minutes.

What healthy looks like

MetricHealthyWorth a lookAct now
Hit ratio (cache)Above 0.900.80 to 0.90Below 0.80, or dropping week over week
Fragmentation1.0 to 1.41.4 to 1.5Above 1.5, or below 1.0 (swap)
EvictionsZero or steadyRising slowlySpiking, or OOM errors on noeviction
Slow logRare, short entriesRepeats over 10 msAny KEYS, or repeats over 50 ms
Big keysNothing over a few MBCollections in the hundreds of thousandsKeys in the hundreds of MB
ReplicationOffset gap near zeroGap growing at peaksync_full climbing

These ranges are common starting points, not Redis defaults. A Redis used as a primary datastore can have a "low" hit ratio and be perfectly healthy.

The pattern behind all six

None of these metrics pages anyone at the moment it goes bad. Hit ratio decays over weeks. Fragmentation builds over months. A big key grows one LPUSH at a time. The KEYS call ships in an innocent-looking PR. Then a traffic spike arrives and all the slack disappears at once.

Point-in-time checks like the ones above catch these only if someone runs them regularly, and the counters reset on every restart, so the history disappears exactly when you need it for a postmortem timeline. The realistic first step is a disciplined manual baseline. Part two of this series walks through a full Redis performance audit with nothing but redis-cli and the tools Redis ships with (INFO, SLOWLOG, LATENCY, MEMORY, --bigkeys) and how to choose the right maxmemory-policy for your workload.

Watch these six continuously

Every check in this guide can run without someone remembering to run it. CloudThinker connects to Redis with a read-only ACL user and tracks hit ratio, fragmentation, evictions, slow commands, big keys and replication lag as trends, flagging drift the week it starts instead of the quarter it becomes an incident. Any fix it proposes waits for your approval. Part three of this series shows how it works.

Related reading

Try CloudThinker free with 100 premium credits and no card required.

redisdatabaseperformancecachingredismonitoringmemoryoptimizationlatency