The goal
Your app uses Redis, and you've been asked to look at it. Redis is an in-memory data store. It's usually a cache, sometimes also a queue or a session store. This post covers the commands you'll use often and the few that can cause an outage.
Step 1: connect
Practice on a throwaway server:
docker run -d --name redis-dev -p 6379:6379 redis:7
docker exec -it redis-dev redis-cli
For a real server:
redis-cli -h redis01.contoso.com -p 6379 --user appuser --askpass
Managed services usually need TLS:
redis-cli -h myredis.redis.cache.windows.net -p 6380 --tls --askpass
--askpass prompts for the password, which keeps it out of your shell history. Test your connection:
PING
INFO server
SELECT 0
DBSIZE
PING should answer PONG. DBSIZE shows the number of keys in the current database.
Step 2: strings and TTLs
A key points to a value. Strings are the simplest kind:
SET session:1001 "asha" EX 3600
GET session:1001
TTL session:1001
EXPIRE session:1001 600
PERSIST session:1001
DEL session:1001
EXISTS session:1001
Reading a TTL result:
TTL returns | Meaning |
|---|---|
| A positive number | Seconds until it expires |
-1 | The key exists and never expires |
-2 | The key doesn't exist |
Counters are also strings, and updates are atomic:
INCR page:views
INCRBY page:views 10
GET page:views
Tip
Give cache keys a TTL unless you have a good reason not to. Keys with no expiry build up until memory runs out. Use a clear naming pattern too, such as
app:type:id.
Step 3: other data types
Each key has one type. Use the right one, and you avoid a lot of application code.
| Type | Good for | Example |
|---|---|---|
| String | Cached values, counters | SET, GET, INCR |
| Hash | An object with fields | HSET, HGET, HGETALL |
| List | Simple queues, recent items | LPUSH, RPOP, LRANGE |
| Set | Unique members | SADD, SISMEMBER, SMEMBERS |
| Sorted set | Rankings, time-ordered items | ZADD, ZRANGE, ZSCORE |
Try them:
HSET user:1001 name "Asha" city "Pune" plan "pro"
HGET user:1001 city
HGETALL user:1001
LPUSH jobs "job-1" "job-2"
LRANGE jobs 0 -1
RPOP jobs
SADD online:users 1001 1002 1003
SISMEMBER online:users 1002
SCARD online:users
ZADD leaderboard 150 "asha" 90 "ravi" 220 "meera"
ZRANGE leaderboard 0 -1 REV WITHSCORES
TYPE user:1001 tells you what kind of key you have.
Step 4: find keys without hurting the server
Redis runs commands one at a time on a main thread, so a slow command makes everyone wait.
# Safe: walks the keys in small steps
redis-cli -h redis01 --scan --pattern 'session:*' | head -20
# Rough view of the biggest keys
redis-cli -h redis01 --bigkeys
Inside the shell:
SCAN 0 MATCH session:* COUNT 100
SCAN returns a cursor and some keys. Call it again with the new cursor until it returns 0.
Caution
Avoid these on production:
KEYS *blocks the server while it reads every key.FLUSHALLandFLUSHDBdelete all data. Check the server name twice, and keep them restricted with ACLs.HGETALL,SMEMBERSorLRANGE 0 -1on very large keys also block.DELon a huge key can stall the server. UseUNLINK, which frees the memory in the background.
Step 5: check health and memory
INFO memory
INFO stats
INFO replication
CONFIG GET maxmemory
CONFIG GET maxmemory-policy
MEMORY USAGE user:1001
CLIENT LIST
SLOWLOG GET 10
The fields to look for:
| Field | Section | Meaning |
|---|---|---|
used_memory_human | memory | Memory used by data |
maxmemory_human | memory | The limit. 0 means none |
mem_fragmentation_ratio | memory | Much higher than 1.5 suggests fragmentation |
evicted_keys | stats | Keys removed because of the memory limit |
keyspace_hits, keyspace_misses | stats | Whether the cache is working |
connected_clients | clients | Compare with maxclients |
role | replication | master or replica |
Work out the cache hit rate:
hit rate = keyspace_hits / (keyspace_hits + keyspace_misses)
A sudden drop in hit rate can overload the database behind the cache. Some managed services block or rename a few of these commands.
Common errors
| Error | Meaning | Fix |
|---|---|---|
NOAUTH Authentication required | You haven't logged in | Reconnect with credentials, or run AUTH |
WRONGPASS | Bad username or password | Check the secret, and the user |
NOPERM | Your ACL doesn't allow the command or key | Ask for the right permission |
WRONGTYPE | Wrong command for the key's type | Check with TYPE key |
OOM command not allowed | Memory limit reached, and policy won't evict | See memory full |
READONLY | You're writing to a replica | Connect to the primary |
MOVED | Redis Cluster: the key is on another node | Use redis-cli -c or a cluster client |
MISCONF | Disk snapshot failed, so writes stop | See the MISCONF fix |
Is the data safe?
By default, think of Redis as fast and not necessarily durable. Depending on the configuration, a restart can lose recent writes, or even all of them.
CONFIG GET save
CONFIG GET appendonly
| Setting | Effect |
|---|---|
save has values | Periodic snapshots (RDB) |
appendonly yes | Write log (AOF), which loses less on a crash |
| Both off | All data is lost on restart |
If the data matters, read about persistence. If it's only a cache, plan for the app to refill it.
Prevent it next time
- Set
maxmemoryand an eviction policy that suits the use. - Require a password or ACL, use TLS and never expose port 6379 to the internet.
- Monitor memory, evictions, hit rate and connected clients.
- Keep the redis-cli cheat sheet handy, and read about caching patterns next.