Redis OOM Error: ‘command not allowed when used memory limit reached’ on Alpine Linux

Written by

in

Troubleshoot Redis OOM errors on Alpine Linux, common in containerized environments. Learn to analyze memory, adjust limits, and optimize Redis for production stability.

Introduction

As an experienced Systems Administrator, encountering Redis Out-Of-Memory (OOM) errors is a critical incident that can bring applications to a halt. The specific error message "OOM command not allowed when used memory limit reached" indicates that your Redis instance has hit its configured maxmemory threshold and, crucially, is configured with a noeviction policy, preventing it from automatically removing keys to free up space. This is particularly common in resource-constrained environments like Docker containers running Alpine Linux, where memory limits are often tightly controlled. When this occurs, your application will experience command failures, timeouts, and data unavailability, leading to a degraded user experience or complete service outage.

This guide will provide a highly technical, accurate, and step-by-step approach to diagnose, understand, and resolve this critical Redis OOM issue on Alpine Linux environments.

Symptom & Error Signature

When Redis reaches its maxmemory limit with a noeviction policy, all write commands (and some read commands depending on specific configuration) will be blocked. You will typically observe the following:

1. Application Logs: Your application (e.g., PHP, Python, Node.js) will receive errors from its Redis client library:

# Example PHP client error
[2026-07-18 10:30:05] app.ERROR: RedisException: OOM command not allowed when used memory > 'maxmemory' in /app/vendor/phpredis/phpredis/src/Redis.php:123
Stack trace:
#0 /app/src/Service/CacheService.php(45): Redis->setEx()

Example Python client error Traceback (most recent call last): File "myapp.py", line 25, in <module> r.set("user:123", "data") File "/usr/local/lib/python3.9/site-packages/redis/client.py", line 1914, in set return self.execute_command('SET', args, *kwargs) File "/usr/local/lib/python3.9/site-packages/redis/client.py", line 1021, in execute_command return self.executecommand(conn, command_name, args, *kwargs) File "/usr/local/lib/python3.9/site-packages/redis/client.py", line 1047, in executecommand response = conn.read_response() File "/usr/local/lib/python3.9/site-packages/redis/connection.py", line 828, in read_response raise self.read_error() redis.exceptions.ResponseError: OOM command not allowed when used memory > 'maxmemory' (bytes) `

2. Redis Server Logs: The Redis server itself will log warnings indicating the OOM condition:

1:M 18 Jul 2026 10:30:00.123 # WARNING: OOM command not allowed when used memory > 'maxmemory' (1073741824 bytes)

3. redis-cli Output: Direct attempts to write data via redis-cli will also fail:

redis-cli SET mykey myvalue
(error) OOM command not allowed when used memory > 'maxmemory' (1073741824 bytes)

Root Cause Analysis

The "OOM command not allowed" error on Alpine Linux, or any other OS, points to a fundamental conflict between available memory, configured limits, and the Redis eviction policy.

  1. maxmemory Limit Reached: This is the primary trigger. Redis is configured with a maxmemory directive in its redis.conf (or via CONFIG SET) which sets an explicit upper bound on the amount of memory it will use for data. When the used_memory metric (reported by INFO memory) exceeds this threshold, Redis enters an OOM state.
  1. noeviction Policy: The choice of maxmemory-policy dictates Redis's behavior when maxmemory is reached.
  2. * If maxmemory-policy is set to noeviction (which is often the default or chosen for critical data stores), Redis will return OOM errors for all write commands (e.g., SET, LPUSH, HSET) and some read commands that might potentially create new keys or increase memory usage (e.g., GETSET, SADD if a set key doesn't exist).
  3. * Other policies (e.g., allkeys-lru, volatile-ttl) would attempt to evict keys to free up space, preventing the OOM error but potentially losing data.
  1. Actual Memory Consumption: The memory usage within Redis can grow due to several factors:
  2. * Data Growth: Natural increase in the number of keys or the size of values stored.
  3. * Temporary Keys: Keys without TTLs that accumulate over time.
  4. * Memory Fragmentation: The memfragmentationratio (from INFO memory) indicates how efficiently Redis is using physical memory. A high ratio (e.g., > 1.5) means Redis is consuming significantly more physical RAM than its reported used_memory due to the underlying memory allocator.
  5. * Client Output Buffers: Large or numerous client connections can consume significant memory for output buffers.
  6. * Replication Buffers: Master-replica replication links maintain buffers for changes, which can grow large, especially if replicas fall behind.
  7. * RDB/AOF Background Saves: During a background save operation (BGSAVE or BGREWRITEAOF), Redis uses a copy-on-write mechanism. If data changes significantly during a save, the memory footprint can temporarily double.
  8. * Lua Scripting: Complex or long-running Lua scripts can hold onto memory.
  1. Alpine Linux & Docker Specifics:
  2. Container Resource Limits: In Docker or Kubernetes, the container itself has memory limits (e.g., --memory flag for docker run, resources.limits.memory in Kubernetes). It's crucial that the Redis maxmemory setting is less than the container's memory limit. If Redis's usedmemoryrss (Resident Set Size) approaches or exceeds the container's limit, the OS's OOM killer will terminate the entire container*, which is much more disruptive than Redis simply refusing commands.
  3. * Memory Allocator: Alpine Linux by default uses musl libc for its C standard library, which includes a simple malloc implementation. Official Redis builds typically link against jemalloc on Linux, which is highly optimized for Redis's allocation patterns and generally results in lower fragmentation. If your Redis build on Alpine is using musl's malloc, you might experience higher memory fragmentation and less efficient memory utilization compared to a jemalloc build. You can check mem_allocator in INFO memory.

Step-by-Step Resolution

Resolving this OOM issue requires a systematic approach, combining immediate mitigation with long-term optimization and scaling strategies.

1. Analyze Current Redis Configuration and Memory Usage

First, gather critical information about your Redis instance. If running in Docker, you'll need to execute commands inside the container.

# Example: Accessing a Dockerized Redis instance

— OR —

Example: Accessing a directly installed Redis instance redis-cli `

Once connected to redis-cli:

# Check current maxmemory limit and eviction policy
CONFIG GET maxmemory

Get detailed memory statistics INFO memory

Expected important output from INFO memory: # used_memory: The total number of bytes allocated by Redis using its allocator (usually jemalloc) # usedmemoryrss: The number of bytes that Redis allocated as reported by the operating system. # usedmemorypeak: The maximum memory consumed by Redis (in bytes) since server startup. # memfragmentationratio: usedmemoryrss / used_memory. A ratio > 1 means fragmentation. # maxmemory_human: The configured maxmemory limit in human-readable format. # maxmemory_policy: The configured eviction policy. # mem_allocator: The memory allocator used (e.g., "jemalloc-5.1.0", "libc")

Check connected clients (can consume memory for output buffers) INFO clients

Check persistence information (RDB/AOF background saves consume temporary memory) INFO persistence `

[!IMPORTANT] A memfragmentationratio significantly above 1.0 (e.g., 1.5+) indicates memory fragmentation. If memallocator is libc, especially on Alpine, this could be a contributing factor. If usedmemory_rss is close to your Docker container's memory limit, you risk container OOM kills.

2. Identify Memory Consumers

Pinpoint which keys or operations are consuming the most memory.

# Identify large keys (requires Redis 4.0+)
# This is a good starting point, but can be slow on very large databases
# Replace <prefix>* with actual key patterns if known

For more detailed memory breakdown (Redis 4.0+) redis-cli MEMORY STATS

Monitor commands in real-time (use cautiously in production due to overhead) # This can help identify commands that might be creating large objects or many keys rapidly. redis-cli MONITOR `

If running in Docker, monitor the container's resource usage:

docker stats <redis-container-id-or-name>

Look for trends in MEM USAGE / LIMIT.

3. Adjust Redis maxmemory and maxmemory-policy (Short-term / Mitigation)

This step provides immediate relief but might not be a long-term solution without further optimization.

A. Increase maxmemory (Temporary Relief or Resource Upgrade)

If you have available RAM on your host or can increase your container's memory limit, raising maxmemory can alleviate the immediate pressure.

[!WARNING] Increasing maxmemory without addressing underlying data growth is merely a band-aid. Also, ensure your new maxmemory value is comfortably below your Docker container's memory limit to prevent container OOM kills. A good rule of thumb is maxmemory < containermemorylimit * 0.8 to account for overhead.

Method 1: Via redis-cli (Runtime – temporary until restart)

# Example: Set maxmemory to 2GB (2147483648 bytes)
CONFIG SET maxmemory 2gb

Method 2: Via redis.conf (Persistent)

Edit your redis.conf file (typically located at /etc/redis/redis.conf or in your Docker volume mount) and modify the maxmemory directive.

# /etc/redis/redis.conf or mounted config file
maxmemory 2gb

After modifying redis.conf, you must restart the Redis service or container:

# For a non-containerized Redis instance (e.g., Systemd on Ubuntu)

For a Docker container docker restart <redis-container-id-or-name> `

B. Adjust maxmemory-policy (Data Loss Risk vs. Availability)

Changing the eviction policy can prevent the OOM error by allowing Redis to automatically delete keys. This is suitable for Redis instances primarily used as a cache.

[!IMPORTANT] Carefully consider the implications of changing maxmemory-policy. Policies other than noeviction will result in data loss when the maxmemory limit is hit. Choose a policy that aligns with your application's data criticality.

Common eviction policies: * noeviction: (Current problematic state) Returns errors on write operations when maxmemory is reached. Use for critical data. allkeys-lru: Evicts keys least recently used (LRU) from all* keys until maxmemory is respected. Ideal for general-purpose caching. volatile-lru: Evicts LRU keys only among those with an expire set*. Useful if you mix persistent and cache data. allkeys-random: Evicts random keys from all* keys. volatile-random: Evicts random keys only among those with an expire set*. allkeys-ttl: Evicts keys with the shortest time to live (TTL) from all* keys. volatile-ttl: Evicts keys with the shortest time to live (TTL) only among those with an expire set*.

To change the policy:

Method 1: Via redis-cli (Runtime – temporary until restart)

# Example: Set policy to allkeys-lru for a cache
CONFIG SET maxmemory-policy allkeys-lru

Method 2: Via redis.conf (Persistent)

Edit your redis.conf file:

# /etc/redis/redis.conf or mounted config file
maxmemory-policy allkeys-lru

Then restart Redis as described above.

4. Optimize Data Structures and Application Usage

This is a crucial long-term strategy to reduce Redis's memory footprint.

  • Set TTLs for Transient Data: Ensure that session data, temporary caches, and other non-persistent data automatically expire.
  • `bash
  • SET mytempkey "some data" EX 3600 # Expires in 1 hour
  • `
  • Use Efficient Data Structures:
  • * Hashes for Related Fields: Instead of SET user:1:name "Alice", SET user:1:email "[email protected]", use a single hash: HSET user:1 name "Alice" email "[email protected]". Hashes (especially "ziplist" encoded ones for small numbers of fields/values) are more memory-efficient than many individual string keys.
  • * Bitmaps for Booleans/Flags: For many on/off flags, bitmaps are extremely memory-efficient.
  • * HyperLogLogs for Unique Counts: For approximate unique counts (e.g., unique visitors), HyperLogLogs (PFADD, PFCOUNT) use fixed, small amounts of memory regardless of the number of unique items.
  • Avoid Large Keys/Values: Very large lists, sets, hashes, or string values consume significant memory. Consider breaking them down or offloading large binary data to object storage.
  • Connection Pooling: Ensure your application uses connection pooling to manage client connections efficiently, reducing the number of active clients and their associated output buffers.

5. Scale Redis Resources (Long-term / Scaling)

When optimization isn't enough, scaling is necessary.

  • Vertical Scaling: Increase the RAM allocated to the VM or Docker container running Redis. This is often the simplest first step if you have available host resources.
  • `bash
  • # Example for Docker compose
  • services:
  • redis:
  • image: redis:7-alpine
  • deploy:
  • resources:
  • limits:
  • memory: 2G # Increase to 2GB
  • `
  • Remember to also adjust Redis's maxmemory accordingly to utilize the new resources.
  • Horizontal Scaling (Redis Cluster): For very large datasets or high throughput, consider a Redis Cluster. This shards your data across multiple Redis nodes, distributing memory and CPU load. This requires significant application-level changes and operational complexity.
  • Read Replicas: If your workload is read-heavy, offload read queries to Redis replicas, reducing the load (and potentially memory usage if client buffers are an issue) on the primary instance.

6. Tune Alpine/Docker Memory Allocator (Advanced)

If you suspect memory fragmentation is a major issue (high memfragmentationratio) and your INFO memory shows mem_allocator: libc on Alpine, you might benefit from using jemalloc.

# Check current allocator
redis-cli INFO memory | grep mem_allocator
  • Official Redis Docker Images: The official redis:<version>-alpine Docker images typically ship with Redis compiled to use jemalloc. If you're using a custom Dockerfile or a non-official image, you might not have jemalloc.
  • Building with jemalloc: If you're building Redis from source on Alpine, ensure jemalloc is included. This usually involves installing jemalloc-dev and configuring Redis with MALLOC=jemalloc.
  • `dockerfile
  • # Example Dockerfile snippet for building Redis with jemalloc on Alpine
  • FROM alpine:3.18
  • RUN apk add –no-cache gcc make musl-dev jemalloc-dev tcl
  • WORKDIR /tmp/redis
  • RUN wget http://download.redis.io/releases/redis-7.0.11.tar.gz &&
  • tar xvzf redis-7.0.11.tar.gz &&
  • cd redis-7.0.11 &&
  • make MALLOC=jemalloc &&
  • make install

… rest of your Redis setup … ` > [!IMPORTANT] > Switching memory allocators requires rebuilding Redis and is a non-trivial change. It should be thoroughly tested. For most users, simply using the official redis:alpine Docker images is sufficient as they are pre-optimized.

7. Implement Robust Monitoring and Alerting

Proactive monitoring is key to preventing future OOM issues.

  • Key Metrics to Monitor:
  • * used_memory: Absolute memory usage.
  • * usedmemoryrss: Physical memory consumed.
  • * memfragmentationratio: Detects memory fragmentation.
  • * keys: Number of keys.
  • * expires: Number of keys with TTLs.
  • * evicted_keys: (If using an eviction policy) indicates when Redis is actively deleting keys.
  • * blocked_clients: Number of clients blocked by commands (can indicate issues).
  • Alerting: Set up alerts for when usedmemory (or usedmemory_rss) exceeds a predefined threshold (e.g., 70-80% of maxmemory or container limit) to provide early warning. Also, alert on OOM command not allowed errors in logs.
  • Tools: Utilize monitoring solutions like Prometheus + Grafana, Datadog, New Relic, or custom scripts to collect and visualize Redis metrics.

By systematically applying these steps, you can effectively troubleshoot and resolve the "Redis OOM command not allowed when used memory limit reached" error, ensuring the stability and performance of your applications.

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *