Troubleshooting Redis OOM: 'Maximum Memory Limit Reached OOM Command Not Allowed'
Diagnose and resolve the 'Redis maximum memory limit reached OOM command not allowed' error, preventing data writes and service interruptions. Optimize Redis memory usage and configuration for stability.
Introduction
Encountering the “Redis maximum memory limit reached OOM command not allowed” error indicates a critical issue where your Redis server has consumed all its allocated memory and is refusing write operations. This typically manifests as sudden application failures, inability to save new data to Redis (e.g., user sessions, cache entries, queue items), and a general degradation of services relying on Redis. While read operations might still function, any attempt to modify data will be met with an error, effectively crippling your application’s dynamic functionality. This guide will walk you through diagnosing the root causes and implementing robust solutions to restore stability and prevent future occurrences.
Symptom & Error Signature
When Redis hits its configured maxmemory limit and is unable to evict keys according to its maxmemory-policy, it enters an Out-Of-Memory (OOM) state. In this state, by default or with a noeviction policy, it will reject write commands.
You will typically observe this error in:
- Application Logs: Errors reported by your application framework (PHP, Node.js, Python, Ruby on Rails) when trying to write to Redis.
- Redis Server Logs: Direct OOM warnings from the Redis instance itself.
- Redis CLI: Attempts to execute write commands manually will fail.
Example Application Log Output (PHP/Predis):
[2023-10-27 14:35:12] app.ERROR: Predis\ClientException: OOM command not allowed when used_memory > 'maxmemory'. in /var/www/html/vendor/predis/predis/src/Client.php:370
Stack trace:
#0 /var/www/html/vendor/predis/predis/src/Client.php(303): Predis\Client->onErrorResponse()
#1 /var/www/html/vendor/predis/predis/src/Client.php(329): Predis\Client->executeCommand()
#2 /var/www/html/app/Services/CacheService.php(80): Predis\Client->__call()
#3 /var/www/html/app/Http/Controllers/UserController.php(45): App\Services\CacheService->set()
...
Example Redis Server Log Output:
12345:M 27 Oct 2023 14:35:12.678 # OOM command not allowed when used_memory is greater than 'maxmemory' (configured as 512mb)
Example Redis CLI Interaction:
redis-cli
127.0.0.1:6379> SET mykey "hello"
(error) OOM command not allowed when used_memory > 'maxmemory'.
Root Cause Analysis
The “Redis maximum memory limit reached OOM command not allowed” error stems from a fundamental imbalance between the data stored in Redis and the memory allocated to it. The primary underlying reasons include:
- Insufficient
maxmemoryConfiguration: The most common cause is that themaxmemorydirective in yourredis.confis set too low for your application’s actual data storage needs. As data accumulates, Redis hits this ceiling. - Ineffective
maxmemory-policy: Redis’smaxmemory-policydictates how it behaves when themaxmemorylimit is reached.- If set to
noeviction(the default for Redis without a specific policy), Redis will stop accepting write commands and return an OOM error. - If set to an eviction policy (e.g.,
allkeys-lru,volatile-lru), but there are no keys eligible for eviction, or the eviction process cannot keep up with the incoming writes, the OOM error can still occur.
- If set to
- Application Memory Leaks or Inefficient Usage:
- Unbounded Data Structures: Lists, Sets, or Hashes that continuously grow without proper trimming or expiration.
- Large Keys: Storing extremely large strings, objects, or serialized data.
- Missing Key Expirations: Data that should be temporary (e.g., cache entries, session tokens) is not given a
TTL(Time-To-Live) and persists indefinitely. - High Churn Rates: Rapid creation of many temporary keys without efficient eviction, leading to memory pressure.
- Traffic Spikes: A sudden, unexpected surge in application traffic or data writes can quickly push Redis beyond its memory limits if not properly provisioned.
- Persistence Overhead: When Redis performs an RDB snapshot or AOF rewrite, it forks a child process. This child process shares memory with the parent via copy-on-write. If
maxmemoryis set very close to the total system RAM, this forking can momentarily double the memory footprint, potentially triggering system-level OOM killer or making Redis unable to persist. While this usually results in a system OOM, it can exacerbate Redis’s memory pressure.
Step-by-Step Resolution
Addressing this error requires a methodical approach, starting with diagnosis and moving towards configuration adjustments and application-level optimizations.
1. Understand Current Redis Memory Usage and Configuration
Begin by inspecting the current state of your Redis instance.
- Connect to Redis CLI:
redis-cli - Get Memory Information:
Pay close attention to:127.0.0.1:6379> INFO memoryused_memory_human: Current memory consumption by Redis.maxmemory_human: The configured maximum memory limit.maxmemory_policy: The current eviction policy.mem_fragmentation_ratio: Ratio ofused_memory_rsstoused_memory. A high ratio (>1.5) indicates fragmentation, wasting memory.
- Check
maxmemoryandmaxmemory-policyspecifically:127.0.0.1:6379> CONFIG GET maxmemory 127.0.0.1:6379> CONFIG GET maxmemory-policy - Examine Key Space:
This shows the number of keys and keys with expires per database.127.0.0.1:6379> INFO keyspace
2. Analyze Redis Key Usage and Data Structures
Identify which keys or data structures are consuming the most memory.
- Find Big Keys: The
redis-cli --bigkeyscommand can help identify the largest keys in your instance.
This command iterates over all keys and reports the largest keys of each data type (string, list, hash, set, zset).redis-cli --bigkeys - Review Application Code: This is crucial. Examine how your application interacts with Redis:
- Are lists or hashes growing indefinitely without trimming or expiration?
- Are large objects being stored as single string keys?
- Are temporary cache items or sessions being created without
EXPIREtimes?
3. Adjust maxmemory Limit (Increase Cautiously)
If used_memory is consistently at or near maxmemory, and your system has available RAM, increasing the maxmemory limit is often the quickest temporary fix.
-
Identify Available System RAM:
free -hEnsure your server has sufficient free RAM. Do not allocate all available RAM to Redis.
-
Temporarily (Runtime) Increase
maxmemory:redis-cli CONFIG SET maxmemory 512mb # Example: Increase to 512MB[!WARNING] This change is not persistent. It will revert to the value in
redis.confupon Redis restart. Use this only for immediate relief while you implement a permanent solution. -
Permanently Increase
maxmemory:- Edit Redis Configuration File:
sudo nano /etc/redis/redis.conf # Or for a specific instance, e.g., /etc/redis/6379.conf - Locate and Modify
maxmemory: Find themaxmemorydirective. If it’s commented out, uncomment it. Adjust the value based on your server’s available RAM and Redis’s role.# Old: # maxmemory <bytes> # New: maxmemory 512mb # Or 1gb, 2gb, etc.[!IMPORTANT] Memory Allocation Best Practices:
- Do not set
maxmemoryto 100% of your system’s RAM. Leave adequate memory for the operating system, other system processes, and especially for Redis’s persistence mechanisms (RDB/AOF). When Redis forks a child process for persistence, memory usage can temporarily spike, potentially doubling for RDB snapshots. - A good starting point is often 50-70% of the total dedicated RAM for the Redis instance.
- Do not set
- Restart Redis Service:
For Dockerized Redis:sudo systemctl restart redis-server
Ensure your Docker Compose ordocker restart <redis_container_name_or_id>docker runcommand for Redis includes the-maxmemoryflag or links to a customredis.conf.
- Edit Redis Configuration File:
4. Configure an Effective maxmemory-policy
If your maxmemory-policy is noeviction, Redis will not automatically free up space. Changing this policy allows Redis to evict keys to make room for new data.
- Edit Redis Configuration File:
sudo nano /etc/redis/redis.conf - Locate and Modify
maxmemory-policy: Choose a policy that fits your use case.
Common# Old: maxmemory-policy noeviction # New (example for general caching): maxmemory-policy allkeys-lrumaxmemory-policyoptions:noeviction: (Default) Returns errors on write commands when memory limit is reached.allkeys-lru: Evicts the least recently used (LRU) keys among all keys. Ideal for general-purpose caching.volatile-lru: Evicts LRU keys only among those that have an expire set. Useful if some keys are essential and should never be evicted.allkeys-lfu: Evicts the least frequently used (LFU) keys among all keys. (Available since Redis 4.0)volatile-lfu: Evicts LFU keys only among those that have an expire set.allkeys-random: Evicts random keys among all keys.volatile-random: Evicts random keys only among those that have an expire set.volatile-ttl: Evicts keys only among those that have an expire set, preferring those with the shortest remaining TTL.
[!IMPORTANT] Carefully consider your
maxmemory-policy. If Redis is used for critical data that should not be lost (rather than just a cache), thennoevictionmight be appropriate, and the real solution lies in increasingmaxmemoryor optimizing data structures. If used as a cache, anLRUorLFUpolicy is usually preferred. - Restart Redis Service:
sudo systemctl restart redis-server
5. Optimize Application-Level Redis Usage
This is often the most sustainable long-term solution.
- Implement Key Expiration (TTL): For cache entries, sessions, or temporary data, always set a
TTLusingEXPIREorSETEX.# Example in Python using redis-py redis_client.setex("user:session:123", 3600, "session_data_here") # Expires in 1 hour - Trim Growing Lists: If using lists as queues or activity streams, use
LTRIMto keep them bounded.127.0.0.1:6379> RPUSH mylist item1 item2 item3 127.0.0.1:6379> LTRIM mylist 0 99 # Keep only the last 100 items - Use Hashes for Related Data: Instead of storing many small individual keys, group related attributes into a single Hash data type. This reduces key overhead.
# Instead of: # SET user:1:name "Alice" # SET user:1:email "[email protected]" # Use: HMSET user:1 name "Alice" email "[email protected]" - Avoid Storing Large Blobs: If you need to store very large objects, consider if Redis is the right tool, or if they can be stored in a file system/object storage and Redis only stores the pointer/metadata.
- Code Review for Anti-Patterns: Look for patterns that fetch all keys (
KEYS *- avoid in production!), or add data without any expiration or trimming logic. - Sharding or Clustering: For very high-scale applications, consider distributing your data across multiple Redis instances (sharding) or using Redis Cluster.
6. Monitor and Alert
Proactive monitoring can prevent future OOM issues.
- Monitor Key Metrics: Use monitoring tools (e.g., Prometheus/Grafana, Datadog, New Relic) to track:
used_memorymaxmemorymem_fragmentation_ratioevicted_keys(indicates your eviction policy is working)keyspace_hitsandkeyspace_misses- System-level RAM usage.
- Set Up Alerts: Configure alerts for high memory usage (e.g., when
used_memoryexceeds 80-90% ofmaxmemory) to get notified before an OOM condition occurs.
7. Consider Redis Persistence Settings
If using RDB snapshots or AOF persistence, ensure these are configured thoughtfully regarding memory.
- RDB and AOF Rewrite: As mentioned in Root Cause Analysis, these operations involve forking. Ensure
maxmemoryis not so close to total system RAM that a fork causes a system OOM. vm.overcommit_memory: On Linux, ensurevm.overcommit_memoryis set to1(the default in many systems) to allow the kernel to overcommit memory. This is crucial for Redis’s copy-on-write mechanism during persistence. You can check withsysctl vm.overcommit_memoryand set it persistently in/etc/sysctl.conf.# Check current value sysctl vm.overcommit_memory # If not 1, set it (temporary) sudo sysctl vm.overcommit_memory=1 # To make it persistent, edit /etc/sysctl.conf sudo nano /etc/sysctl.conf # Add or modify the line: vm.overcommit_memory = 1 # Then apply changes sudo sysctl -p[!WARNING] While
vm.overcommit_memory=1is generally recommended for Redis persistence, understand that it tells the kernel to allow processes to allocate more memory than physically available. This relies on processes not actually using all that memory simultaneously. A misbehaving process could still trigger system OOM.
By systematically applying these steps, you can effectively resolve the “Redis maximum memory limit reached OOM command not allowed” error and establish a more robust, performant, and stable Redis environment.
