which eviction fits when
A poorly chosen maxmemory-policy leads either to write commands being rejected in the middle of production or to the silent loss of important data that was actually meant to persist. Understanding how Redis manages memory under pressure lets you pick the right policy deliberately instead of by accident, avoiding both outcomes reliably.
Table of Contents
- 1. What a maxmemory-policy actually controls
- 2. The eight maxmemory-policy options at a glance
- 3. noeviction: when Redis refuses write commands
- 4. allkeys-lru and volatile-lru in detail
- 5. allkeys-lfu and volatile-lfu: frequency over recency
- 6. volatile-ttl and volatile-random
- 7. Choosing the right maxmemory-policy for pure caches
- 8. maxmemory-policy for primary store and mixed workloads
- 9. Monitoring, benchmarking and switching in production
- 10. Summary
- 11. FAQ
1. What a maxmemory-policy actually controls
As soon as Redis reaches the memory limit configured in maxmemory, the engine has to decide what happens to new write commands. That decision is exactly what the maxmemory-policy defines. It is not a side setting but one of the most consequential configuration options in any Redis deployment, because it directly determines whether data may be discarded and by what criterion that happens. Without a deliberately set maxmemory-policy, Redis runs with the default value noeviction, which is the wrong choice for many production setups.
Choosing the right maxmemory-policy depends entirely on what Redis is used for. If the instance serves as a pure cache in front of a relational database, data loss under memory pressure is uncritical as long as the right data gets evicted. If Redis instead serves as a primary store for sessions, counters or queues, any uncontrolled data loss is an incident. This distinction runs through the whole article and is the most important factor when choosing a maxmemory-policy.
Technically, the maxmemory-policy only kicks in once used_memory exceeds the configured limit and a new write command would require additional memory. Redis then checks before every command whether memory needs to be freed, selects candidates according to the active policy, and removes them before the actual command runs. This happens synchronously inside the event loop, which is why the choice of maxmemory-policy also has a direct effect on the latency of individual commands.
2. The eight maxmemory-policy options at a glance
Redis offers eight possible values for maxmemory-policy, which differ along two dimensions: the key range candidates are chosen from, and the criterion used for eviction. The key range is either allkeys, which includes every key, or volatile, which only considers keys with a TTL set. The criterion is LRU, LFU, TTL, random or no eviction at all. This combination produces the eight options that every maxmemory-policy decision essentially maps to.
It is important to read the naming convention correctly: allkeys-lru means eviction happens across all keys based on least-recently-used, regardless of whether a TTL is set. volatile-lru applies the same criterion only to keys with a TTL. Keys without an expiration stay untouched under every volatile variant of the maxmemory-policy, even when memory is full. If a volatile policy finds no key with a TTL, Redis behaves like noeviction and rejects write commands.
# redis.conf: basic maxmemory-policy configuration
maxmemory 2gb
maxmemory-policy allkeys-lru
# Available values for maxmemory-policy:
# noeviction: no eviction, write errors once memory is full
# allkeys-lru: LRU across all keys
# volatile-lru: LRU only across keys with a TTL
# allkeys-lfu: LFU (access frequency) across all keys
# volatile-lfu: LFU only across keys with a TTL
# allkeys-random: random selection across all keys
# volatile-random: random selection only across keys with a TTL
# volatile-ttl: shortest remaining lifetime first
3. noeviction: when Redis refuses write commands
The noeviction policy is the default value and the most conservative option among all maxmemory-policy variants. Once memory reaches the configured limit, Redis stops accepting new write commands and responds with the error OOM command not allowed when used memory > maxmemory. Read commands keep working normally, only commands that require additional memory are rejected. This maxmemory-policy is the right choice when data loss is fundamentally unacceptable and the application can handle the resulting error cleanly instead.
In practice, noeviction is mostly sensible for Redis instances that serve as a primary store for critical state, such as shopping cart data, distributed locks or business-relevant counters. The downside of this maxmemory-policy is obvious: without active capacity planning it leads to a production outage as soon as memory is exhausted. Applications must explicitly catch the OOM error, otherwise the error propagates unchecked all the way to the user.
A common misunderstanding: noeviction does not prevent existing keys with an expired TTL from being removed. The TTL mechanism operates independently of the maxmemory-policy and continues to remove expired keys lazily on access and actively via sampling. Only memory-pressure-based eviction is disabled by noeviction, not the regular expiration logic.
# Configure noeviction and handle the OOM error in the application
redis-cli CONFIG SET maxmemory-policy noeviction
redis-cli SET user:session:8842 "..."
# (error) OOM command not allowed when used memory > 'maxmemory'.
# Check memory headroom and utilization before hitting the limit
redis-cli INFO memory | grep -E "used_memory:|maxmemory:"
4. allkeys-lru and volatile-lru in detail
LRU stands for Least Recently Used and evicts the keys that have not been accessed for the longest time. Redis does not implement exact LRU but approximated LRU based on sampling, because a full LRU list across millions of keys would mean too much memory overhead and CPU cost. This maxmemory-policy draws five random keys by default, compares their access timestamps and removes the oldest. The maxmemory-samples parameter controls the sample size and therefore the accuracy of the approximation.
The difference between allkeys-lru and volatile-lru lies purely in the key range considered. allkeys-lru is the most widely used maxmemory-policy for pure cache deployments, because every key counts as a potential eviction candidate and the entire memory budget is used efficiently for hot data. volatile-lru, on the other hand, fits mixed instances where some keys must persist permanently and only the keys with a TTL are treated as the cache portion.
# Increase maxmemory-samples for a more accurate LRU approximation
redis-cli CONFIG SET maxmemory-samples 10
# Check current policy and sample size
redis-cli CONFIG GET maxmemory-policy
# 1) "maxmemory-policy"
# 2) "allkeys-lru"
redis-cli CONFIG GET maxmemory-samples
# 1) "maxmemory-samples"
# 2) "10"
# Eviction statistics since server start
redis-cli INFO stats | grep evicted_keys
# evicted_keys:184213
5. allkeys-lfu and volatile-lfu: frequency over recency
LFU stands for Least Frequently Used and evicts keys by access frequency instead of recency. This maxmemory-policy solves a real problem with LRU: a key that has been read thousands of times per hour for weeks and then goes unrequested for ten minutes would still count as an eviction candidate under pure LRU, even though it is statistically very likely to be needed again soon. LFU avoids exactly this misjudgment, because it weighs long-term access frequency more heavily than the most recent point in time.
Redis implements LFU through a probabilistic 8-bit counter per key, stored in the same memory field that holds the timestamp under LRU. This counter increases logarithmically instead of linearly on every access, so that even extremely frequently read keys do not immediately hit the maximum value. In addition, the counter decreases over time via the configurable lfu-decay-time, so old popularity does not keep affecting decisions indefinitely. This maxmemory-policy is particularly well suited for caches with a clear Pareto pattern, where a small number of keys account for most of the traffic.
# redis.conf: LFU fine-tuning
maxmemory-policy allkeys-lfu
lfu-log-factor 10
lfu-decay-time 1
# Read the access frequency of a single key (only valid under an LFU policy)
redis-cli OBJECT FREQ session:user:8842
# (integer) 217
# lfu-log-factor determines how fast the counter saturates under heavy load
# Higher value = finer resolution for very popular keys
6. volatile-ttl and volatile-random
volatile-ttl evicts, among all keys with a TTL set, the ones with the shortest remaining lifetime first. This maxmemory-policy makes sense when keys would expire soon anyway and removing them a little early causes little additional harm, for example short-lived rate-limiting counters or session tokens close to expiry. The advantage over LRU is that the decision is made deterministically from existing metadata, without the sampling cost of tracking access patterns.
volatile-random and allkeys-random remove keys without any weighting by recency or frequency. That sounds like the worst possible choice at first, but it is actually defensible in specific scenarios: if all keys in an instance have roughly the same access probability, for example with evenly distributed access to a large, homogeneous dataset, LRU or LFU brings no measurable advantage over random, while still incurring the CPU overhead of sampling logic. This maxmemory-policy is rarely the first choice, but it is not a fundamental mistake either.
7. Choosing the right maxmemory-policy for pure caches
For Redis instances that run purely as a cache in front of an origin data source, allkeys-lru is the sensible default in most cases, because it delivers good hit rates without fine tuning and uses the entire capacity for hot data. Where clear popularity patterns exist, for example e-commerce product pages where a handful of bestsellers generate most of the requests, allkeys-lfu delivers measurably better hit rates, because it captures this uneven distribution better than pure recency does.
A pure cache should fundamentally never use noeviction, because every cache miss turned into an error instead of a fallback to the origin source is the worst possible failure mode. Likewise, a pure cache should always set a TTL on every key, even though allkeys variants of the maxmemory-policy already evict independently of TTL, because TTLs clean up stale data regardless of memory pressure and keep data consistency with the origin source intact.
8. maxmemory-policy for primary store and mixed workloads
When Redis serves as a primary store, for example for sessions, feature flags or persistent counters, uncontrolled data loss through eviction is a serious risk. Here noeviction combined with careful capacity planning and monitoring is the preferred approach. Alternatively, when part of the data is allowed to expire based on TTL and another part must persist permanently, volatile-lru or volatile-lfu is the right maxmemory-policy, because it only uses the TTL-bearing portion as an eviction buffer and guarantees the rest stays untouched.
In mixed deployments where the same instance holds both cache data and business-critical state, a clear separation by TTL convention is the most robust solution: every cache key always gets a TTL, every primary-store key stays without an expiration, and the maxmemory-policy is set to volatile-lru or volatile-lfu. That way Redis only evicts the cache portion and leaves critical data untouched, even under memory pressure.
| maxmemory-policy | Key range | Criterion | Typical use case |
|---|---|---|---|
| noeviction | none | no eviction | primary store, critical state |
| allkeys-lru | all keys | least recently used | pure cache, default case |
| volatile-lru | TTL keys only | least recently used | mixed cache and primary store |
| allkeys-lfu | all keys | least frequently used | cache with Pareto distribution |
| volatile-ttl | TTL keys only | shortest remaining lifetime | short-lived tokens, rate limits |
9. Monitoring, benchmarking and switching in production
The maxmemory-policy can be changed at any time in production via CONFIG SET, without restarting Redis. The change takes effect immediately for future eviction decisions but does not alter data already stored. Before every switch, INFO memory and INFO stats should be captured as a baseline, in particular the fields used_memory, evicted_keys and keyspace_hits relative to keyspace_misses, to compare hit rate before and after the change objectively.
For a reliable comparison between two maxmemory-policy candidates, a controlled A/B test under realistic load is recommended, because synthetic benchmarks rarely produce the same access distribution as production traffic. redis-cli --latency-history shows whether a policy causes noticeable latency spikes, while evicted_keys per minute reveals the actual eviction rate. Anyone who regularly observes high eviction counts with a low hit rate should either raise the memory limit or switch the maxmemory-policy, instead of ignoring the symptom.
# Switch policy live without a restart
redis-cli CONFIG SET maxmemory-policy allkeys-lfu
# Calculate hit rate
redis-cli INFO stats | grep -E "keyspace_hits|keyspace_misses"
# keyspace_hits:9821223
# keyspace_misses:412887
# Observe latency spikes during eviction phases
redis-cli --latency-history -i 5
# Persist the change into redis.conf (CONFIG SET alone does not persist)
redis-cli CONFIG REWRITE
Mironsoft
Redis operations, caching architecture and performance tuning
Is the wrong maxmemory-policy costing you hit rate or data?
We analyze your Redis workloads, measure access patterns and jointly choose the right maxmemory-policy for cache and primary store instances, with monitoring that surfaces wrong decisions early.
Workload analysis
Determine access patterns and distribution before choosing a policy
Configuration
Set maxmemory-policy, samples and lfu-decay-time for production
Monitoring
Keep hit rate, evictions and latency permanently in view
10. Summary
The maxmemory-policy decides what happens to data once Redis hits its memory limit, which makes it one of the most important operational decisions of all. noeviction protects critical data at the cost of write errors once memory is full. allkeys-lru and allkeys-lfu maximize the hit rate of pure caches, with LFU having the edge under uneven popularity distributions. volatile variants of the maxmemory-policy enable mixed workloads by using only TTL-bearing keys as the eviction buffer.
The right choice does not come from gut feeling but from the role the Redis instance plays: pure cache, primary store or mixed workload. Monitoring evicted_keys, hit rate and latency before and after every switch provides the data basis to evaluate the maxmemory-policy objectively, instead of relying on assumptions. Since the policy can be switched at any time without a restart, controlled experimentation in production pays off more than pure theory.
maxmemory-policy Compared: The Essentials at a Glance
For pure caches
allkeys-lru as a solid default, allkeys-lfu when a clear popularity pattern with few bestsellers exists.
For primary store
noeviction with capacity planning, or volatile-lru when only part of the data has cache characteristics.
Switchable live
CONFIG SET maxmemory-policy takes effect immediately, CONFIG REWRITE persists it into redis.conf.
Monitoring fields
Compare evicted_keys, keyspace_hits and keyspace_misses before and after every switch.