Redis Monitoring with Native Tools: A Hands-On Performance Audit
Five fields from a single INFO call answer roughly 80% of Redis health questions: used_memory (against maxmemory), mem_fragmentation_ratio, keyspace_hits, keyspace_misses, and evicted_keys. If you can read those five and know what to do when each looks wrong, you're ahead of most teams running Redis in production. This guide is a complete redis monitoring audit using nothing but redis-cli and the commands Redis ships with — no exporters, no dashboards, nothing to install.
In part one of this series we covered the metrics that matter and what bad looks like: collapsing cache hit ratio, memory fragmentation, eviction storms, O(N) commands blocking the event loop, big keys, hot keys, and replication lag. This article is the audit itself, tool by tool, in the order you'd actually run it. Budget 1–2 hours for a first pass on a single production instance.
One ground rule before you start: Redis is single-threaded for command execution. Every diagnostic you run competes with production traffic, so prefer the sampled and throttled variants noted below, and run the heavier passes on a replica where you have one.
Tool 1: INFO — the five numbers, then the rest
INFO is free to run and covers hit ratio, memory, and eviction behavior in one shot (INFO docs).
Step 1: Compute your cache hit ratio
redis-cli INFO stats | grep -E 'keyspace_hits|keyspace_misses'
Hit ratio is keyspace_hits / (keyspace_hits + keyspace_misses). One-liner:
redis-cli INFO stats | awk -F: '/keyspace_hits/{h=$2} /keyspace_misses/{m=$2} END{printf "hit ratio: %.4f\n", h/(h+m)}'
How to read it. For a cache workload, healthy is typically above 0.90; below 0.80 means your database is absorbing traffic Redis was supposed to shield it from. Two caveats: these counters accumulate since the last restart, so on a long-lived instance the ratio smooths over recent regressions — sample it twice, 10 minutes apart, and diff the raw counters for a current-rate view. And if Redis is your primary datastore rather than a cache, a "low" ratio may just be your access pattern.
Step 2: Read the memory section
redis-cli INFO memory | grep -E 'used_memory_human|used_memory_rss_human|maxmemory_human|mem_fragmentation_ratio|maxmemory_policy'
How to read it. mem_fragmentation_ratio is RSS divided by used_memory. Between 1.0 and 1.5 is normal. Above 1.5, the allocator is holding memory Redis freed but can't return — common after mass deletions or heavy key churn. Below 1.0 is worse: the OS has swapped Redis memory to disk, and latency is about to fall off a cliff. If fragmentation is high and you're on a modern build with jemalloc, active defragmentation is the fix that doesn't require a restart:
redis-cli CONFIG SET activedefrag yes
Also check used_memory against maxmemory. If maxmemory is 0 (unset) on a cache instance, that's a finding on its own — Redis will grow until the OS OOM-killer decides otherwise.
Step 3: Evictions and expirations
redis-cli INFO stats | grep -E 'evicted_keys|expired_keys'
redis-cli INFO keyspace
How to read it. expired_keys climbing is healthy — TTLs doing their job. evicted_keys climbing means demand exceeds maxmemory and Redis is throwing data out under pressure; sustained evictions on a cache usually show up as the hit-ratio drop you measured in step 1. INFO keyspace shows keys and expires per database: if expires is a small fraction of keys on a cache workload, a large share of your keyspace has no TTL and will never leave voluntarily. That's your first remediation ticket.
Tool 2: SLOWLOG — the commands stalling the event loop
The slow log records commands whose execution exceeded a threshold — it excludes network time and queueing, so anything in here blocked every other client while it ran (SLOWLOG docs).
Configure a sane window first (threshold is in microseconds; default 10000 = 10 ms):
redis-cli CONFIG SET slowlog-log-slower-than 10000
redis-cli CONFIG SET slowlog-max-len 1024
Then, after letting production traffic run for a while:
redis-cli SLOWLOG GET 25
redis-cli SLOWLOG LEN
How to read it. Each entry shows a timestamp, execution time in microseconds, and the full command with arguments. You're hunting the usual suspects from part one: KEYS * (never in production — replace with SCAN), SMEMBERS/LRANGE 0 -1/HGETALL against large collections, SORT without limits, and huge MGET/pipeline batches. A 50 ms entry means every client stalled 50 ms. Fix pattern: replace full-collection reads with SSCAN/HSCAN/cursor-based LRANGE windows, and break monolithic collections into smaller keys. Run SLOWLOG RESET after remediation so your next audit pass starts clean.
Tool 3: LATENCY — when slowness isn't a slow command
Not all latency comes from expensive commands: forks for RDB snapshots, AOF fsync stalls, transparent huge pages, and expire cycles all cause spikes the slow log never sees. Redis has a built-in latency monitor for exactly this; it's off by default (latency monitor docs).
Enable it with a threshold in milliseconds:
redis-cli CONFIG SET latency-monitor-threshold 100
After it has watched some traffic:
redis-cli LATENCY LATEST
redis-cli LATENCY HISTORY command
redis-cli LATENCY DOCTOR
How to read it. LATENCY LATEST lists each event class with its latest and all-time maximum spike. LATENCY HISTORY takes an event name and gives timestamped samples for it — command covers slow command execution, fork covers snapshot/replication forks, aof-fsync-always covers disk stalls. LATENCY DOCTOR is genuinely useful: it analyzes the samples and produces human-readable advice (it will tell you, for example, if fork latency correlates with instance memory size, or to check THP settings). If fork events dominate on a large instance, your options are less memory per instance, replica-driven persistence, or accepting the spike window.
Tool 4: MEMORY USAGE and MEMORY DOCTOR — per-key accounting
INFO memory gives totals; the MEMORY subcommands attribute them (MEMORY USAGE docs).
# Bytes for one key, sampling all elements (SAMPLES 0 = exact, costs more)
redis-cli MEMORY USAGE user:12345:sessions SAMPLES 0
# Allocator-level breakdown: overhead, dataset, per-db, fragmentation
redis-cli MEMORY STATS
# Built-in advisor
redis-cli MEMORY DOCTOR
How to read it. Use MEMORY USAGE to price the specific keys your slow log and big-key scan implicate — a "small" hash that turns out to hold 40 MB explains a lot of HGETALL pain. In MEMORY STATS, compare overhead.total against dataset.bytes: high overhead relative to data usually means millions of tiny keys, where per-key metadata dominates and hash-field consolidation saves real memory. MEMORY DOCTOR gives blunt advice on fragmentation and allocator health — a quick sanity check that your reading of the numbers matches Redis's own.
Tool 5: redis-cli --bigkeys and --hotkeys — the keyspace sweep
The redis-cli scanning modes walk the keyspace with SCAN, so they don't block the server the way KEYS would — but they still generate load, so throttle them and prefer a replica (redis-cli docs):
# Largest key per type, by element count; -i 0.1 sleeps 100ms per 100 SCAN calls
redis-cli --bigkeys -i 0.1
# Largest keys by actual bytes (uses MEMORY USAGE under the hood)
redis-cli --memkeys -i 0.1
# Most-accessed keys — requires an LFU eviction policy (next section)
redis-cli --hotkeys
How to read it. --bigkeys reports per-type champions by element count; --memkeys is the better signal because it measures bytes. Any single key holding hundreds of MB, or a collection with millions of members, is a finding: big keys serialize slowly, block on delete (use UNLINK, not DEL), and stall replication. --hotkeys only works when maxmemory-policy is one of the LFU policies, because it reads the access-frequency counters LFU maintains — if you're on LRU it will tell you so and exit. A single hot key taking a large share of traffic is your sharding or client-side-caching candidate before the next traffic spike finds it for you.
Choosing a maxmemory-policy
Everything above feeds one configuration decision: what Redis does at the memory ceiling (eviction docs).
redis-cli CONFIG GET maxmemory-policy
redis-cli CONFIG SET maxmemory-policy allkeys-lfu
redis-cli CONFIG REWRITE # persist the change to redis.conf
The short decision table:
| Workload | Policy |
|---|---|
| Pure cache, all keys re-fetchable | allkeys-lfu (or allkeys-lru pre-4.0) |
| Cache plus must-keep keys, TTLs mark the cache | volatile-lfu / volatile-lru |
| Expiry-ordered eviction makes semantic sense | volatile-ttl |
| Primary datastore — losing keys is data loss | noeviction plus real capacity planning |
Two traps. noeviction on a cache means writes start failing with OOM errors at the ceiling instead of quietly evicting — fine for a datastore, an outage for a cache. And any volatile-* policy with few TTL'd keys (check INFO keyspace from step 3) has almost nothing it's allowed to evict, which behaves like noeviction at the worst moment.
Where the DIY audit stops
Run this audit — it will find real problems. But be honest about its structural limits:
It's a snapshot. Hit ratio, fragmentation, and eviction counters describe today. The deploy that ships an unbounded HGETALL next sprint won't announce itself; you'll find it on the next audit, weeks after users felt it.
The counters forget and the logs roll. SLOWLOG holds 1,024 entries and LATENCY HISTORY keeps 160 samples per event — a busy night can rotate the evidence out before you look. Cumulative INFO counters blur regressions into long-run averages unless someone keeps diffing them.
Detection isn't remediation. Nothing above adds a TTL strategy, refactors a big key, or reshards a hot one. Every finding becomes a ticket, and cache-hygiene tickets lose priority fights until the day the hit ratio drops and the database falls over.
The audit is a baseline. The obvious next question is how these checks run continuously, with the fixes attached.
What comes next
Everything in this guide can run on a schedule instead of on a good day. Tony, CloudThinker's database agent, connects to Redis read-only and watches hit ratio, fragmentation, evictions, and the slow log continuously — proposing TTL strategies, eviction-policy changes, and big-key refactors with the evidence attached, gated behind your approval. That's part three of this series. Or see your own instance's findings first: Try CloudThinker free — 100 premium credits, no card required.
