Key design, memory and eviction

Naming conventions that scale, per-key memory accounting, finding big keys, and choosing a maxmemory policy that will not surprise you.

Key design

# colon-separated, type-prefixed keys
SET    user:42:profile:1     '{"name":"Ada"}'
HSET   cart:42:items        sku1 2 sku2 1
ZADD   board:daily:2026-09-18 1500 user:42
EXPIRE user:42:profile:1 3600

# hash tags force related keys onto the same cluster slot
# user:{42}:profile   user:{42}:orders   -> both hash to slot(user:{42})
# note the braces: only the part inside them is used for the slot
  • Prefix with the entity type, then the identifier, then the attribute. A key you cannot understand from MONITOR output is a key you will not be able to debug.
  • Never build a key from unbounded user input without a size limit - a 1 MB key is legal and will be replicated to every replica.
  • Hash tags are required for multi-key operations in cluster mode, but overusing one tag defeats sharding by putting everything on a single slot.
  • Store a version or a schema marker where the shape can change, so a deploy can distinguish old and new formats instead of crashing on a decode error.
⚠️
Without maxmemory and a policy, Redis grows until the operating system kills it - typically by the OOM killer, with no useful log. Setting a limit turns exhaustion into a controlled eviction or a clean write error.

Memory accounting

127.0.0.1:6379> MEMORY USAGE user:42:profile       # bytes for one key
127.0.0.1:6379> MEMORY DOCTOR
127.0.0.1:6379> MEMORY STATS | head -30
127.0.0.1:6379> info memory

# big keys: sampled, but far cheaper than a full walk
redis-cli --bigkeys
redis-cli --memkeys --memkeys-samples 0

# keys with no expiry are the usual cause of unbounded growth
redis-cli --scan --pattern 'cache:*' | head -1000

# why the used_memory number is bigger than your data
# - per-key overhead: a small key is not small
# - allocator fragmentation: mem_fragmentation_ratio
# - client output buffers, replication backlog, AOF buffer
SettingMeaningPractical value
maxmemoryHard limit before the policy applies70-80 percent of container memory, leaving room for COW during fork
maxmemory-policyWhat to evict when fullallkeys-lru for a pure cache
maxmemory-samplesKeys sampled to approximate LRU5 by default; 10 improves accuracy slightly
maxmemory-clientsCap on client buffersProtects against a slow subscriber
activedefragBackground defragmentationjemalloc only; watch the CPU cost
  • A key holding one 8-byte value still costs roughly 60-100 bytes of overhead. Ten million tiny keys cost a gigabyte before any data.
  • Small hashes and lists use compact encodings (listpack) and are far cheaper per element than a key per item.
  • Empty keys disappear: deleting the last field of a hash removes the key, which is convenient and can surprise code that expects EXISTS to keep returning 1.

Eviction policies

CONFIG SET maxmemory 4gb
CONFIG SET maxmemory-policy allkeys-lru
CONFIG SET maxmemory-samples 10

# check what is actually happening
INFO stats | grep evicted_keys
INFO memory | grep -E "maxmemory_policy|mem_fragmentation_ratio"
PolicyEvictsRisk
noevictionNothing, writes fail with OOMCorrect for a queue or a lock store - you lose writes, not data
allkeys-lruLeast recently used of all keysEvicts a session or lock along with cache entries
allkeys-lfuLeast frequently usedBetter when a small hot set matters; needs time to learn
volatile-lruLRU among keys with a TTLNothing is evicted if no keys have a TTL, so writes still fail
volatile-ttlKeys closest to expiryPredictable, but ignores access frequency
# never mix cache and durable data in one instance
# instance A: cache only
maxmemory-policy allkeys-lru

# instance B: locks, queues, sessions
maxmemory-policy noeviction
# and alert on evicted_keys > 0 and on rejected_connections

Mixing a cache and a queue in one instance means the cache policy can silently delete queued work. Separate instances, or at minimum separate volatile-* semantics with every cache key carrying a TTL and every durable key carrying none.

FAQ

How do I find what is using all the memory?
Start with INFO memory for the totals and MEMORY STATS for the breakdown, then redis-cli --bigkeys for outliers. In practice the answer is usually one key pattern with no TTL, not a thousand different keys.
What fragmentation ratio is a problem?
A ratio above about 1.5 means the allocator holds memory it is not using. Restarting usually resolves it; enabling active defragmentation trades CPU for memory. A ratio below 1 means swapping, which is far worse - check the host immediately.

Installing Redis, redis-cli and RESP basics Security: ACLs, TLS and hardening

Last refreshed 2026-09-18.