Memory first: full or fragmented
`INFO memory` is the first stop: `used_memory_human` is actual usage and `maxmemory` the cap (0 means unlimited — dangerous, the OS OOM-killer will step in); a `mem_fragmentation_ratio` above 1.5 indicates fragmentation, common with frequent churn of large values.
When memory is full and the policy is noeviction, writes fail with OOM errors; the application symptom is "intermittent write failures", easily misdiagnosed as a network issue.
redis-cli INFO memory | grep -E "used_memory_human|maxmemory_human|mem_fragmentation"
redis-cli CONFIG GET maxmemoryScan for big keys: the usual culprit
A ZSET with a million members can make one full ZRANGE take seconds, queuing every command behind it. Use `redis-cli --bigkeys` for a low-overhead sampled view of the largest key per type; for precise sizes use `--memkeys` (Redis 6.0+) or MEMORY USAGE per key.
Note that --bigkeys samples via the SCAN cursor and is safe to run in production; never use KEYS * — it walks the whole keyspace in one blocking shot and is a classic outage maker.
redis-cli --bigkeys # 采样找各类型最大 key(安全)
redis-cli MEMORY USAGE <key> # 精确测量单个 keyRead the slowlog: which command drags
The built-in slowlog records commands above a threshold (default 10ms; 1ms captures more clues). `SLOWLOG GET 10` shows the last ten — note the command name, latency and key, then trace the calling code.
The high-latency leaderboard: KEYS, SMEMBERS on big sets, HGETALL on big hashes, full ZRANGE, FLUSHALL/FLUSHDB, long loops in Lua. Replace each: KEYS → SCAN, SMEMBERS → batched SSCAN, HGETALL → HMGET of just the needed fields.
redis-cli CONFIG SET slowlog-log-slower-than 1000 # 阈值降到 1ms
redis-cli SLOWLOG GET 10Eviction policy: the switch for when memory fills
For caches choose allkeys-lru (evict least-recently-used across the keyspace) or allkeys-lfu (hotter precision, 4.0+); for data that must persist choose noeviction, but then scale and alert in advance — write failures are only a matter of time. The volatile-* family only evicts keys with TTLs; if your keys have none, it behaves as noeviction.
Verify immediately after changing policy: push a write burst and confirm no OOM errors. Eviction bursts may add slight latency (many DELs); lazyfree (4.0+) makes deletion asynchronous.
redis-cli CONFIG SET maxmemory-policy allkeys-lru
redis-cli CONFIG SET lazyfree-lazy-eviction yesPersistence jitter: RDB fork and AOF fsync
BGSAVE forks a child, and the fork cost grows with instance size (page-table copy), briefly stalling the main thread — for periodic stalls on big instances check latest_fork_usec in INFO stats. AOF everysec is the balanced default; switching to always fsyncs every write and collapses throughput.
If Redis is a pure cache with rebuildable data, turning persistence off (save "", appendonly no) removes an entire class of jitter — the most common "free" optimization.
redis-cli INFO stats | grep latest_fork_usec # fork 耗时(微秒)Emergency and prevention checklist
Live-incident flow: ① locate the command via SLOWLOG; ② delete big keys with UNLINK (async) instead of DEL; ③ restart non-critical instances if needed. Prevention: ① shard big collections into smaller keys; ② replace full traversal with SCAN cursors; ③ cap maxmemory at 70% of physical RAM; ④ monitor used_memory, slowlog count and replica lag. Paste this checklist into the on-call handbook and Redis MTTR drops by half.
redis-cli UNLINK <big-key> # 异步删除,不阻塞主线程