Redis evicts keys when it runs out of memory, but "running out" is a complex state with multiple escape routes.
Let’s see what happens when we’re low on memory:
# Start a redis server with a small maxmemory limit
redis-cli --port 6379 --save "" --appendonly no --maxmemory 10mb --maxmemory-policy allkeys-lru
# Set a few keys
redis-cli -p 6379 SET key1 "value1"
redis-cli -p 6379 SET key2 "value2"
redis-cli -p 6379 SET key3 "value3"
redis-cli -p 6379 SET key4 "value4"
redis-cli -p 6379 SET key5 "value5"
# Now, try to set a new key that will exceed the limit
redis-cli -p 6379 SET bigkey $(python -c 'print("A"*1024*1024*2')') # 2MB
Redis will likely respond with (error) OOM command not allowed when used as a key. But if we tried to GET a key, it might succeed. Why? Because GET is a read operation, and Redis prioritizes keeping read operations alive when memory is tight. Write operations, like SET, are often blocked.
The core problem Redis eviction policies solve is deciding which keys to remove when maxmemory is reached, to make space for new data, while trying to keep the most valuable data in memory. It’s not just about if it runs out, but how it decides to free up space.
The maxmemory-policy configuration directive is your primary lever here. It dictates the eviction strategy.
Here are the common policies and how they work:
-
noeviction: This is the default. If memory runs out, Redis simply stops accepting write commands. Reads are still allowed. This is the safest if you absolutely cannot afford to lose data and can tolerate write failures.- Diagnosis:
redis-cli config get maxmemory-policywill shownoeviction. Attempting toSETa key whenmaxmemoryis hit will result inOOM command not allowed when used as a key. - Fix:
redis-cli config set maxmemory-policy allkeys-lru(or another policy). This tells Redis to start evicting.
- Diagnosis:
-
allkeys-lru: Evicts the Least Recently Used (LRU) keys among all keys in the database. This is a good general-purpose policy if you expect your access patterns to be somewhat uniform.- Diagnosis:
redis-cli config get maxmemory-policyshowsallkeys-lru. Whenmaxmemoryis hit, Redis will identify and remove the least recently accessed keys. - Fix: No fix needed if this is your desired policy; it’s already active. If you want to change to this policy, use
redis-cli config set maxmemory-policy allkeys-lru.
- Diagnosis:
-
volatile-lru: Evicts the LRU keys among those that have an expiration set. Keys without an expiration are not considered for eviction. This is useful if you have a mix of persistent and time-limited data and want to protect the persistent data.- Diagnosis:
redis-cli config get maxmemory-policyshowsvolatile-lru. Whenmaxmemoryis hit, Redis only looks at keys withTTLset. - Fix: If you want to evict LRU keys from all keys, change to
allkeys-lru. If you want to evict keys that expire soon, considervolatile-ttl.
- Diagnosis:
-
allkeys-random: Evicts random keys from all keys in the database. This is simpler than LRU but less effective at preserving "hot" data. It’s useful for very simple scenarios or when LRU overhead is a concern (though the overhead is generally minimal).- Diagnosis:
redis-cli config get maxmemory-policyshowsallkeys-random. Eviction is probabilistic. - Fix: Change to
allkeys-lrufor better performance if your access patterns are not purely random.
- Diagnosis:
-
volatile-random: Evicts random keys from those that have an expiration set. Similar tovolatile-lrubut uses random selection.- Diagnosis:
redis-cli config get maxmemory-policyshowsvolatile-random. Eviction is random among expired keys. - Fix: Change to
volatile-lruorallkeys-lruif you need more predictable eviction behavior.
- Diagnosis:
-
allkeys-lfu: Evicts the Least Frequently Used (LFU) keys among all keys. This policy tracks the access frequency of keys and removes those accessed least often. It’s often more effective than LRU for workloads with "hot spots" where some keys are accessed vastly more than others.- Diagnosis:
redis-cli config get maxmemory-policyshowsallkeys-lfu. Redis internally maintains a counter for each key’s access frequency. - Fix: No fix needed if this is your desired policy. If you want to change to this, use
redis-cli config set maxmemory-policy allkeys-lfu.
- Diagnosis:
-
volatile-lfu: Evicts the LFU keys among those that have an expiration set.- Diagnosis:
redis-cli config get maxmemory-policyshowsvolatile-lfu. Eviction is LFU-based, but only for keys with TTL. - Fix: Change to
allkeys-lfuif you want to consider all keys for LFU eviction.
- Diagnosis:
Crucially, Redis doesn’t perfectly implement LRU or LFU. It uses a probabilistic approximation to reduce memory overhead. For LRU, it samples a small number of keys and evicts the least recently used among the sample. For LFU, it uses a logarithmic counter to approximate frequency.
When Redis is low on memory and needs to evict, it first tries to find a key to evict based on the chosen policy. If it’s an allkeys policy, it looks across all keys. If it’s a volatile policy, it only looks at keys with an expiration set. If it finds a suitable key (e.g., LRU, LFU, random), it deletes it. If it cannot find a key to evict (e.g., noeviction policy is set, or all remaining keys are protected and cannot be evicted), then write commands will fail.
The next error you’ll encounter after fixing memory issues is likely related to network timeouts if your application isn’t handling Redis connection errors gracefully.