Key names, patterns, and expiry
Redis has no tables or folders. The key name is your schema, and a TTL is how a key cleans itself up.
Name keys like paths
user:42:profile, session:9f2c, rl:ip:1.2.3.4
Version caches: cache:v2:product:42 — bump v2 to drop every old entry at once.
Keep names short but readable; they live in RAM too.
u42 (nobody knows what it is), a full URL or JSON blob as the key, spaces and mixed case, user input pasted straight in without a prefix.
Find keys: KEYS vs SCAN
- KEYS user:* checks every key in one command. With 10 million keys that takes seconds.
- Redis runs one command at a time, so every other client waits behind it: logins, cache reads, everything.
- SCAN 0 MATCH user:* COUNT 100 checks a small slice and returns the next cursor (1840).
- Between slices, other clients' commands run. Nobody waits more than a moment.
- Call SCAN again with each cursor until it returns 0. Same keys, no outage. A key can appear twice, so de-duplicate.
KEYS only on a laptop. In production, SCAN (or HSCAN, SSCAN, ZSCAN inside one big key).Give a key a TTL
| SET k v EX 60 | Write and expire in one atomic command. Prefer this over SET then EXPIRE. |
|---|---|
| EXPIRE k 60 [NX|XX|GT|LT] | Set a TTL on an existing key. NX: only if it has none (rate limiters). |
| EXPIREAT k 1767225600 | Expire at a Unix time: “end of the sale”. |
| TTL / PTTL | Seconds / milliseconds left. |
| PERSIST k | Remove the TTL. A plain SET also removes it unless you pass KEEPTTL. |
How expiry really works
- Redis keeps a second table: key → expiry time. Only keys with a TTL live there. Six of these have passed their time (⌛) but are still in memory.
- Lazy expiry: a client runs GET k7. Redis checks the time, sees it passed, deletes k7, and replies (nil). An expired key is never returned.
- But keys nobody reads would sit in RAM forever. So a background job runs 10 times a second…
- …it picks 20 random keys that have a TTL (here 7, to fit the picture) and deletes the expired ones: k2, k5, k12.
- 3 of 7 were expired — more than 25%. That means many more are probably waiting, so it samples again right away and finds k9 and k14.
- Result: reads are always correct, and memory is reclaimed in small, cheap steps instead of one big scan.
Watch active expiry
Lab · 60 keys, a sampler, and the 25% rule
Press “Time passes”, then run cycles. Watch how a high expired ratio triggers extra samples.
Expiry is not eviction
You set a TTL. When it passes, the key is gone, even if memory is empty.
Memory hits maxmemory. The maxmemory-policy picks victims: allkeys-lru, allkeys-lfu, volatile-lru (only keys with a TTL), volatile-ttl, or noeviction (writes fail instead).
Quick check
SET session:abc … again to update it. What happened to its 30-minute TTL?
Show answer
It is gone — a plain SET clears the TTL, and the session now lives forever. Use SET … EX 1800 or KEEPTTL, or update a hash field with HSET, which keeps the TTL.
INFO memory still counts it. Is that a bug?
Show answer
No. Nobody touched it yet (lazy) and the sampler has not picked it yet (active). Reads already return (nil); memory follows shortly.