Redis’s maxmemory-policy is less about choosing a strategy and more about deciding which data you don’t want to keep when memory is full.
Let’s see it in action. Imagine a simple cache where we store user session data, keyed by session ID.
{
"user:123": {"session_data": "...", "timestamp": 1678886400},
"user:456": {"session_data": "...", "timestamp": 1678886460},
"user:789": {"session_data": "...", "timestamp": 1678886520}
}
We’ve set maxmemory 10mb and maxmemory-policy allkeys-lru. As we add more users, eventually Redis will need to evict something. With allkeys-lru (Least Recently Used across all keys), it looks at all keys and evicts the one that hasn’t been accessed in the longest time. If user:123 was accessed last, it’s the prime candidate for eviction.
This policy is great for general-purpose caching. It tries to keep the data that’s most likely to be used again by discarding the least recently accessed items.
Another common scenario is a time-series database where older data is less relevant. If we were storing metrics:
{
"metric:cpu:server1:2023-03-15T10:00:00": 0.85,
"metric:cpu:server1:2023-03-15T10:01:00": 0.87,
"metric:mem:server2:2023-03-15T10:00:00": 0.60
}
And we set maxmemory-policy volatile-ttl. This policy only considers keys with an EXPIRE set. It then evicts the key that will expire soonest. If metric:cpu:server1:2023-03-15T10:00:00 has an EXPIRE set for 5 minutes from now, and others have 10 or 15 minutes, this metric is gone first. This is useful when you’re explicitly setting TTLs on your data and want Redis to manage the cleanup based on those TTLs.
The core problem maxmemory-policy solves is preventing Redis from crashing when it runs out of memory. You’re telling Redis, "When you’re full, here’s how to make space." Without a policy, Redis will simply return an error on write operations.
Internally, when maxmemory is reached and a new write operation occurs, Redis consults the maxmemory-policy. It then performs a series of checks and evictions based on that policy until enough space is freed for the new write.
The exact levers you control are maxmemory (the absolute memory limit in bytes) and maxmemory-policy (the eviction strategy). The policies themselves are:
noeviction: Return errors on writes when memory is full.allkeys-lru: Evict the Least Recently Used (LRU) keys across all keys.volatile-lru: Evict the LRU keys among those with an expire set.allkeys-random: Evict random keys across all keys.volatile-random: Evict random keys among those with an expire set.volatile-ttl: Evict keys with an expire set, prioritizing those with the shortest TTL.allkeys-lfu: Evict the Least Frequently Used (LFU) keys across all keys.volatile-lfu: Evict the LFU keys among those with an expire set.
Choosing allkeys-lfu or volatile-lfu is often the most performant for caches that have seen sustained, heavy read traffic over time. These policies are generally better at identifying and removing truly stale data because they consider access frequency rather than just recency. An item accessed thousands of times recently is more likely to be useful than an item accessed only once recently, and LFU accounts for this.
The most surprising thing about LFU policies is that they don’t track the exact number of times a key has been accessed. Instead, they use a probabilistic counter that increments with a decaying probability. This clever trick keeps the memory overhead of tracking frequency very low, making it practical for Redis to implement.
The next step after understanding eviction is to monitor Redis memory usage and eviction rates.