Diagnosing slow Redis means knowing what blocks the main thread and how data is laid out in memory.
Redis executes commands on one main thread driven by an event loop (epoll/kqueue). That's why commands are atomic and why throughput is high without locks, but also why one slow command delays every client. Since Redis 6, optional I/O threads (io-threads) parse requests and write replies in parallel, and Redis 8 improved this substantially, but command execution itself stays serial. Background threads handle UNLINK/lazy freeing, AOF fsync and closing files.
Common causes of latency:
- O(N) commands on big keys:
KEYS,HGETALL/SMEMBERS/LRANGE 0 -1on huge collections,DELof a big key (useUNLINKand lazyfree options), - slow Lua scripts,
- fork for RDB/AOF rewrite on large instances, plus transparent huge pages making copy-on-write expensive (disable THP),
- swapping, and
appendfsync alwayson slow disks.
Tools: SLOWLOG GET lists commands slower than slowlog-log-slower-than (microseconds), LATENCY DOCTOR and --latency measure, INFO commandstats shows per-command totals.
Encodings: small collections use compact sequential layouts. Hashes, zsets and lists use listpack while small, sets of integers use intset, and they convert to hash tables, skiplists or quicklists when they exceed thresholds like hash-max-listpack-entries (128) or a value exceeds hash-max-listpack-value (64 bytes). OBJECT ENCODING key shows the current one. Keeping collections under thresholds can cut memory several-fold.
Example
redis-cli HSET small f1 v1 # (integer) 1
redis-cli OBJECT ENCODING small # "listpack"
redis-cli SADD ids 1 2 3 # (integer) 3
redis-cli OBJECT ENCODING ids # "intset"
redis-cli HSET small f2 "$(printf 'x%.0s' $(seq 1 100))" # value > 64 bytes
redis-cli OBJECT ENCODING small # "hashtable"
redis-cli ZADD z 1 a # (integer) 1
redis-cli OBJECT ENCODING z # "listpack" (skiplist when large)
redis-cli CONFIG SET slowlog-log-slower-than 10000 # log commands > 10 ms
redis-cli SLOWLOG GET 5 # id, timestamp, microseconds, command
redis-cli INFO commandstats | head -3 # cmdstat_hset:calls=...,usec_per_call=...Remember
- One main thread executes all commands; I/O threads only help with networking
- Big keys, O(N) commands, slow scripts and forks cause latency spikes
- SLOWLOG, LATENCY DOCTOR and commandstats locate them
- Small collections use listpack/intset encodings that save lots of memory
Watch out for
- Adding io-threads to fix a CPU-bound slow command: execution is still single-threaded.