/인프라/Redis OOM command not allowed Error: A 5-Minute Diagnosis and Recovery Guide
InfrastructureRedisOOM command not allowed

Redis OOM command not allowed Error: A 5-Minute Diagnosis and Recovery Guide

A practical 5-minute diagnosis and recovery guide for when Redis rejects writes with 'OOM command not allowed when used memory > maxmemory'. Confirm used_memory, change maxmemory-policy, clean up big keys and TTLs with copy-paste commands,

Redis OOM command not allowed Error: A 5-Minute Diagnosis and Recovery Guide

Redis "OOM command not allowed" Error: A 5-Minute Practical Diagnosis and Recovery Guide

Are SET and LPUSH failing one after another in your application logs, with 5xx errors firing? And are you seeing this error from Redis?

CODE
(error) OOM command not allowed when used memory > 'maxmemory'.

Let me put this in one sentence first. This is neither the Linux kernel's OOMKilled nor the JVM's OutOfMemoryError: Java heap space. The Redis process is still alive; it has hit its internal maxmemory limit, and because maxmemory-policy=noeviction, it is refusing write commands only. In other words, the process is not dead — it is blocking writes by policy, which is expected behavior. That is why recovery is fast. Let's jump in.

How the Error Happens: Why Writes Are Rejected but Reads Still Work

When used_memory reaches maxmemory, Redis decides what to do based on the configured maxmemory-policy. If the policy is the default or is explicitly set to noeviction, Redis never deletes existing data and instead rejects write commands that would accept new data.

CODE
used_memory ≥ maxmemory  +  policy = noeviction
        │
        ├─ SET / LPUSH / HSET / SADD / INCR ...  →  ❌ OOM 에러 (거부)
        └─ GET / LRANGE / HGETALL / EXISTS ...   →  ✅ 정상 (허용)

Reads still work for a simple reason: they do not increase memory usage. noeviction is safe for a DB-of-record where you cannot afford to lose a single piece of data, but for a pure cache it actually becomes a source of outages. The key is either free memory or change the policy — one of the two.

5-Minute Instant Diagnosis: Four Copy-Paste Commands

We are in an incident, so skip the explanation and run the commands first. Start by checking memory status in a single line.

Bash
redis-cli INFO memory | grep -E "used_memory:|used_memory_human|maxmemory:|maxmemory_human|maxmemory_policy|mem_fragmentation_ratio"

How to read the output:

  • used_memory_humanmaxmemory_human → you have hit the limit
  • maxmemory_policy:noeviction → the direct cause of write rejection
  • mem_fragmentation_ratio → 1.5 or higher means excessive fragmentation (the OS is holding more than the actual data)

Next, look at detailed stats and the built-in diagnosis.

Bash
redis-cli MEMORY STATS      # peak.allocated, dataset.bytes 등 상세 분해
redis-cli MEMORY DOCTOR     # Redis가 직접 진단 메시지를 줌
redis-cli CONFIG GET maxmemory*   # maxmemory, maxmemory-policy 현재값 확인

If MEMORY DOCTOR reports something like "high fragmentation" or that peak memory is 1.5× the current value, that is your hint for the next action.

💡 Watch out in container environments: If you leave maxmemory at 0 (unlimited) in Docker/Kubernetes, Redis has no idea about the cgroup memory limit. Then you will not get this OOM error — the kernel will OOMKill the container. Those are completely different symptoms. In containers, always set maxmemory explicitly to about 70–75% of the memory limit.

Immediate Recovery + Root-Cause Cleanup

Step 1: Decide on the policy

The path splits depending on whether this Redis is a cache or the source of record for the data.

PolicyBehaviorWhen to useRisk / notes
noevictionReject writes when the limit is hit; preserve dataData that must not be lost (queues, session source of record, DB-of-record)Immediate outage once memory is full. Capacity increase is required
allkeys-lruEvict by LRU across all keysPure cache (the source still exists in a DB)More cache misses. Data loss if any keys have no source of record
volatile-ttlEvict keys that have a TTL, soonest-to-expire firstMix of TTL keys and persistent keysKeys without a TTL are never evicted, so memory can fill up again

Decision rule: If the data in Redis also exists in a DB or elsewhere, allkeys-lru is almost always the right answer. If this is the only copy — session store, queue, and the like — keep noeviction and increase memory instead.

Step 2: Apply it with no downtime

CONFIG SET takes effect immediately at runtime with no restart.

Bash
# 런타임 즉시 반영 (서비스 중단 없음)
redis-cli CONFIG SET maxmemory-policy allkeys-lru

# 적용 확인
redis-cli CONFIG GET maxmemory-policy

That one line unblocks writes immediately. But it is volatile. A restart will revert to the original setting. Also update redis.conf so the change persists.

Config
# redis.conf
maxmemory 4gb
maxmemory-policy allkeys-lru
Bash
# 현재 런타임 설정을 conf 파일에 기록 (주의: 주석/포맷이 재작성됨)
redis-cli CONFIG REWRITE

⚠️ CONFIG REWRITE has Redis rewrite the existing redis.conf. Hand-written comments can disappear, so if you manage conf via configuration management (Ansible/Helm), it is safer to edit the source conf directly and rolling-redeploy instead of using REWRITE.

Step 3: Hunt down big keys and keys without a TTL

Changing the policy put out the fire, but you still need to find what is eating the memory to prevent a repeat.

Bash
# 데이터 타입별 가장 큰 키 탐지
redis-cli --bigkeys

# 메모리를 가장 많이 쓰는 키 (Redis 6.2+)
redis-cli --memkeys

# 특정 키의 실제 메모리 사용량(byte)
redis-cli MEMORY USAGE mybigkey

And keys without a TTL never disappear, so they are the main cause of memory accumulation. Never run KEYS * on a production Redis. It blocks the single thread and creates another outage. Always inspect with SCAN, walking the cursor.

Bash
# 커서 기반 논블로킹 순회
redis-cli SCAN 0 COUNT 100

# 특정 키의 TTL 확인 → -1 이면 만료 없음(영구 키)
redis-cli TTL session:abc123
# (integer) -1   ← 이런 키들이 쌓이면 메모리가 계속 찬다

If you see cache-like keys whose TTL is -1, the real fix is to change the application so it sets an expiry together with the write, for example SET key value EX 3600.

Sizing maxmemory and Preventing Recurrence

Sizing formula

The standard is to set maxmemory to about 70–75% of physical memory (or the container limit). The remaining 25–30% is headroom for Copy-on-Write on fork during RDB/AOF saves, client output buffers, and the OS page cache. Without that headroom, a real OOMKill happens during background saves.

Bash
# 예: 물리 메모리 6GB 인스턴스 → 약 70%인 4GB
redis-cli CONFIG SET maxmemory 4gb

Monitoring and alerts

To stop hitting this outage over and over, an 80% threshold alert is essential. The current standard is Prometheus plus redis_exporter.

PROMQL
# used_memory가 maxmemory의 80%를 넘으면 경고
redis_memory_used_bytes / redis_memory_max_bytes > 0.8

When this alert fires, you have time to review the policy, scale up, and clean big keys before OOM actually hits. Note that Valkey, the Redis fork, is compatible with the same maxmemory/maxmemory-policy settings and the commands above, so you can use this post's commands as-is.

One line from the field

The most commonly reported cause was leaving the default noeviction policy in place on a pure cache. For cache use, pinning allkeys-lru at setup time and adding a code convention that forces TTLs is enough to make most of these outages disappear.

Post-recovery checklist

  • Confirm the intended policy with CONFIG GET maxmemory-policy
  • Persist maxmemory and maxmemory-policy in redis.conf
  • Clean up abnormal big keys with --bigkeys
  • Give expiry to cache keys whose TTL is unset (-1)
  • Confirm the Prometheus 80% alert is working

References: Official docs

The primary source for the behavior, settings, and errors covered in this post is the official documentation below. Check there for version-specific options and exact behavior.

FAQ

Q. If I change to CONFIG SET maxmemory-policy allkeys-lru, are keys deleted immediately? A. If you are already at the limit, some keys will be evicted in LRU order so new writes can be accepted. That is safe if the source still exists in a DB, but if Redis is the only copy there is a risk of data loss — keep noeviction and increase memory instead.

Q. Is this the same as Linux OOMKilled? A. No. This error means the Redis process is still alive and is refusing writes according to its internal maxmemory policy. OOMKilled means the kernel killed the process itself due to memory pressure. If you leave maxmemory at 0 in a container, you get the latter.

Q. Can I use KEYS * to inspect keys in production? A. Absolutely not. KEYS * blocks the single thread and causes latency spikes or a full outage. Always walk the cursor with SCAN.

확인 정보
✦ ✦ ✦
편집 검토 · Editorial Review

Nodelog는 모든 콘텐츠의 내용과 출처를 공개 전에 검토합니다. 환경(OS·버전)에 따라 결과가 달라질 수 있는 기술 정보는 공식 문서와 함께 확인하며, 검토 기준과 정정 원칙은 편집 정책에서 안내합니다. 오류를 발견하시면 이메일로 제보해 주세요 — 확인 후 신속히 정정합니다.

편집 책임 · Nodelog 기술 편집팀·발행 · ·업데이트 ·
관련 공식 문서Redis 공식 문서

Comments

Be the first to comment.