Introduction Redis reports `OOM command not allowed` when `used_memory_rss` exceeds `maxmemory`, even if the actual data (`used_memory`) is well below the limit. This discrepancy is caused by memory fragmentation—the allocator reserves more memory from the OS than Redis needs for its data structures, and freed memory is not returned efficiently.

Symptoms - `INFO memory` shows `mem_fragmentation_ratio` greater than 1.5 or 2.0 - `used_memory` is below `maxmemory` but `used_memory_rss` exceeds it - OOM errors despite seemingly available memory - `used_memory_peak` significantly higher than current `used_memory` - Gradual increase in fragmentation ratio over days or weeks of operation

Common Causes - Mix of different key sizes causing allocator fragmentation - Large number of key deletions leaving fragmented memory holes - jemalloc allocator not configured or compiled without Redis - Long-running Redis process without restart, accumulating fragmentation - Workload pattern with frequent create/delete cycles of varying-sized values

Step-by-Step Fix 1. **Diagnose memory fragmentation**: ```bash redis-cli INFO memory | grep -E "used_memory:|used_memory_rss:|mem_fragmentation_ratio:|allocator_" # Example output: # used_memory:1073741824 (1 GB actual data) # used_memory_rss:2147483648 (2 GB resident set) # mem_fragmentation_ratio:2.00 # allocator_active:1610612736 # allocator_allocated:1073741824 ```

  1. 1.Enable active defragmentation:
  2. 2.```bash
  3. 3.redis-cli CONFIG SET activedefrag yes
  4. 4.redis-cli CONFIG SET active-defrag-enabled yes
  5. 5.redis-cli CONFIG SET active-defrag-threshold-lower 10
  6. 6.redis-cli CONFIG SET active-defrag-threshold-upper 100
  7. 7.redis-cli CONFIG SET active-defrag-cycle-min 5
  8. 8.redis-cli CONFIG SET active-defrag-cycle-max 75
  9. 9.redis-cli CONFIG SET active-defrag-max-scan-fields 1000

# Monitor defragmentation progress redis-cli INFO memory | grep -E "active_defrag|fragmentation" ```

  1. 1.If defragmentation is not enough, restart Redis to reclaim memory:
  2. 2.```bash
  3. 3.# Save current state
  4. 4.redis-cli BGSAVE
  5. 5.redis-cli LASTSAVE

# Verify the RDB file redis-check-rdb /var/lib/redis/dump.rdb

# Restart sudo systemctl restart redis-server

# Verify fragmentation after restart redis-cli INFO memory | grep mem_fragmentation_ratio # Should be close to 1.0 ```

  1. 1.Configure jemalloc for better fragmentation handling:
  2. 2.```bash
  3. 3.# Check which allocator Redis is using
  4. 4.redis-cli INFO memory | grep allocator
  5. 5.# Should show: mem_allocator:jemalloc-5.x.x

# If using libc malloc, rebuild Redis with jemalloc # make MALLOC=jemalloc ```

  1. 1.Reduce fragmentation by optimizing key patterns:
  2. 2.```bash
  3. 3.# Instead of many small individual keys, use hashes
  4. 4.# BAD: SET user:1:name "John", SET user:1:email "john@example.com"
  5. 5.# GOOD: HSET user:1 name "John" email "john@example.com"

# Compress large string values python3 -c " import redis, zlib, json r = redis.Redis() data = {'large': 'payload' * 10000} r.set('my:key', zlib.compress(json.dumps(data).encode())) " ```

Prevention - Monitor `mem_fragmentation_ratio` and alert when it exceeds 1.5 - Enable active defragmentation (`activedefrag yes`) by default on production - Use Redis 6.0+ with improved jemalloc integration - Keep data structures consolidated (use Hash instead of many individual keys) - Plan restarts during maintenance windows for long-running instances - Set `maxmemory` based on `used_memory_rss`, not `used_memory` - Use `MEMORY PURGE` command to ask the allocator to release memory back to the OS: ```bash redis-cli MEMORY PURGE ```