How it works
The explanation, with examples you can run.
Mostly single-threaded
"Single-threaded" describes command execution, not the whole process. Redis uses background threads for things like closing files and freeing large values (UNLINK frees memory off the main thread, unlike DEL), and forks a child process for snapshots. Since Redis 6 it can also use I/O threads (io-threads, off by default) to read and write sockets in parallel; the commands themselves still run one at a time. To use many cores for commands, you run several Redis processes, or a cluster.
The trap: one slow command
The flip side of one command at a time is that a slow command stops everyone. Commands are not all O(1):
KEYS user:* # walks every key in the database; debugging onlySMEMBERS big:set # returns every member; fine for 50, not for 5 millionDEL huge:hash # frees every field on the main thread; UNLINK does it in the backgroundLRANGE log 0 -1 # the whole listWhile one of these runs, every other client's command waits. The usual fixes: SCAN (and HSCAN, SSCAN, ZSCAN) iterate with a cursor in small batches; UNLINK instead of DEL for large keys; keep collections bounded; keep Lua scripts short. The slow log records commands over a threshold:
CONFIG SET slowlog-log-slower-than 10000 # microsecondsSLOWLOG GET 10Snapshotting has a similar effect: fork() of a process with a large memory footprint can pause the main thread for milliseconds or more.
Round trips cost more than commands
A command that takes a microsecond on the server may take half a millisecond or more to travel over the network and back. A loop of 1,000 GETs, each waiting for its reply, spends almost all its time waiting. Two fixes:
- Multi-key commands:
MGET k1 k2 k3,HMGET,MSET. - Pipelining: the client writes many commands without waiting, then reads all the replies. Redis executes them in order; other clients' commands may run in between, so a pipeline is not a transaction.
# Send three commands in one go from the shell; --pipe reports a summary, not each replyprintf 'SET a 1\r\nINCR a\r\nGET a\r\n' | redis-cli --pipe# All data transferred. Waiting for the last reply...# Last reply received from server.# errors: 0, replies: 3In application code, client libraries expose pipelines directly (a pipeline() or batch object that queues commands and sends them together).
What this means for design
Keep values and collections at sizes where each command is cheap. Prefer commands that do the work on the server (INCR, ZADD, HINCRBY) over reading, changing and writing back from the client. And treat Redis as a shared resource: one service running an expensive command can slow down every other service using the same instance.
Check yourself
3 questions. Get them all right to finish this topic.
0 of 3 right so far. Get all three to finish this topic.