/인프라/Redis OOM 에러(used memory > maxmemory) 5분 응급처치 가이드
인프라Redis OOMmaxmemory

Redis OOM 에러(used memory > maxmemory) 5분 응급처치 가이드

Redis "OOM command not allowed when used memory > maxmemory" 에러를 INFO memory 진단부터 maxmemory 증설, allkeys-lru eviction 정책, TTL 재발 방지까지 복붙 명령어로 단계별 해결합니다.

Redis OOM 에러(used memory > maxmemory) 5분 응급처치 가이드

Redis OOM 에러(used memory > maxmemory) 5분 응급처치 완벽 가이드

배포도 안 했는데 갑자기 운영 로그에 이런 메시지가 도배되기 시작합니다.

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

읽기는 되는데 SET, INCR, LPUSH 같은 쓰기 명령만 전부 거부되는 상황. 세션 저장소나 캐시로 Redis를 쓰고 있다면 그대로 서비스 장애로 직결됩니다. 이 글은 "지금 장애 중"인 분을 위해 응급 처치를 앞에, 원인 분석을 뒤에 배치했습니다. 아래 로드맵대로 따라오면 5분 안에 쓰기를 복구할 수 있습니다.

CODE
[1] INFO memory 로 현황 파악 (30초)
[2] maxmemory 늘리거나 / eviction 정책 바꿔 즉시 복구 (1분)
[3] CONFIG REWRITE 로 영구 저장 (10초)
[4] TTL · 모니터링으로 재발 방지 (이후)

1. 30초 현황 파악: INFO memory 읽는 법

가장 먼저 지금 Redis가 어떤 상태인지 봐야 합니다.

Bash
redis-cli INFO memory
CODE
# Memory
used_memory:2147483648
used_memory_human:2.00G
used_memory_rss:2415919104
used_memory_rss_human:2.25G
maxmemory:2147483648
maxmemory_human:2.00G
maxmemory_policy:noeviction
mem_fragmentation_ratio:1.12
mem_allocator:jemalloc-5.3.0

핵심 지표 4개만 봅니다.

지표의미판별 기준
used_memoryRedis가 논리적으로 쓰는 메모리maxmemory에 근접/도달하면 위험
used_memory_rssOS가 실제로 점유한 물리 메모리(RSS)used_memory보다 과도하게 크면 단편화
mem_fragmentation_ratiorss ÷ used_memory1.0~1.4 정상 / 1.5↑ 단편화 / 1.0 미만 스왑 의심
maxmemory_policy한계 도달 시 동작noeviction이면 쓰기 거부의 직접 원인

위 예시는 used_memory == maxmemory이고 정책이 noeviction입니다. 즉, 메모리가 꽉 찼고 비울 정책도 없으니 쓰기를 거부하는 전형적 상황입니다.

보조 명령도 알아두면 좋습니다.

Bash
redis-cli MEMORY DOCTOR          # Redis가 직접 진단 코멘트를 줌
redis-cli MEMORY USAGE mykey     # 특정 키가 차지하는 바이트

2. 즉시 복구: maxmemory 조정과 정책 선택

상황은 둘 중 하나입니다. (A) 메모리를 더 줄 수 있다 또는 (B) 캐시라서 일부 버려도 된다.

(A) 메모리 여유가 있으면 한계만 올린다

서버 RAM에 여유가 있다면 maxmemory를 무중단으로 늘립니다.

Bash
redis-cli CONFIG SET maxmemory 4gb

이 명령은 즉시 적용되고, 직후부터 쓰기가 다시 동작합니다.

(B) 순수 캐시라면 eviction 정책을 켠다

캐시 용도인데 noeviction으로 운영했다면 이게 근본 문제입니다. LRU 기반으로 오래된 키를 자동으로 밀어내게 합니다.

Bash
redis-cli CONFIG SET maxmemory-policy allkeys-lru

정책을 바꾸는 순간 한계 초과분이 evict되며 쓰기가 즉시 복구됩니다.

maxmemory-policy 8종 비교표

상황에 맞는 정책을 고르는 것이 핵심입니다.

정책동작대상 키캐시용세션·영속용
noeviction한계 도달 시 쓰기 거부(에러)-◎(증설 전제)
allkeys-lru가장 오래 안 쓴 키 제거전체
allkeys-lfu가장 적게 쓰인 키 제거전체◎(추천 증가)
volatile-lruTTL 있는 키 중 LRUTTL 키만
volatile-lfuTTL 있는 키 중 LFUTTL 키만
allkeys-random무작위 제거전체
volatile-randomTTL 키 중 무작위TTL 키만
volatile-ttl만료 임박 키 우선 제거TTL 키만◎(TTL 혼재)

선택 가이드

  • 순수 캐시: allkeys-lru 또는 접근 빈도 편차가 큰 경우 allkeys-lfu
  • TTL 키와 영속 키가 섞인 환경: volatile-ttl 또는 volatile-lru (TTL 없는 키는 보호됨)
  • 데이터 유실이 절대 불가(세션·큐·영속 저장): noeviction 유지 + 메모리 증설이 정답. 정책으로 버티려 하지 마세요.

영구 저장

CONFIG SET은 재시작하면 사라집니다. 반드시 설정 파일에 반영합니다.

Bash
redis-cli CONFIG REWRITE

또는 redis.conf를 직접 수정해 둡니다.

Config
maxmemory 2gb
maxmemory-policy allkeys-lru
maxmemory-samples 5

maxmemory-samples는 LRU/LFU가 제거 후보를 고를 때 표본 수입니다. 기본 5면 충분하고, 정밀도를 높이려면 10까지 올릴 수 있지만 CPU를 더 씁니다.

3. 원인 진단: OOM을 부르는 5가지 시나리오

복구했다면 이제 왜 터졌는지 봅니다. 증상→원인→확인 순서로 정리합니다.

① maxmemory 한계 도달

  • 증상: used_memory ≈ maxmemory, 쓰기 전면 거부
  • 원인: 데이터 증가량이 할당 메모리를 초과
  • 확인: INFO memory에서 두 값 비교

② 정책이 noeviction

  • 증상: 캐시인데도 키를 안 버리고 에러만 냄
  • 원인: 기본값 noeviction을 캐시에 그대로 사용
  • 확인: CONFIG GET maxmemory-policy

③ 메모리 단편화로 실질 부족

  • 증상: used_memory는 여유 있는데 OOM 또는 OS 스왑 발생
  • 원인: 잦은 키 생성/삭제로 jemalloc 단편화, RSS가 부풀어 OS 메모리 압박
  • 확인: mem_fragmentation_ratio 1.5 이상

④ RDB/AOF rewrite의 fork(COW) 압박

  • 증상: BGSAVE/AOF rewrite 시점에 메모리 급증, fork 실패 로그
  • 원인: fork 시 Copy-On-Write로 쓰기가 많으면 부모 메모리가 복제됨. 최악엔 2배까지 순간 점유
  • 확인: 로그의 Can't save in background: fork: Cannot allocate memory, INFO persistencerdb_last_bgsave_status

⑤ 키에 TTL 미설정으로 무한 누적

  • 증상: 시간이 갈수록 used_memory가 단조 증가
  • 원인: 캐시인데 만료를 안 걸어 영원히 살아있는 키
  • 확인: redis-cli --bigkeys, DBSIZE 추세 관찰

실무 경험담: 제가 겪은 OOM의 절반 이상은 ⑤번, TTL 누락이었습니다. 코드 리뷰에서 "이 SET에 EX 빠졌어요" 한 줄이면 막을 일을, 몇 달 뒤 새벽 장애로 되갚는 경우가 많습니다. 정책 튜닝보다 TTL 컨벤션 강제가 비용 대비 효과가 가장 큽니다.

4. 재발 방지 체크리스트

캐시 키엔 무조건 TTL을 건다. 쓰기 시점에 만료를 함께 지정하세요.

Bash
SET session:1234 "payload" EX 3600     # 1시간
SETEX cache:user:99 600 "..."          # 10분

단편화 대응. Redis 4.0+의 활성 디프래그를 켭니다.

Bash
redis-cli CONFIG SET activedefrag yes

단편화가 심해 RSS가 안 빠지면 마지막 수단으로 재시작 시 RSS가 회수됩니다(단, 데이터 영속화 후 진행).

모니터링 알람. redis_exporter + Prometheus + Grafana로 메모리 사용률 80%에서 알람을 겁니다.

YAML
groups:
  - name: redis-memory
    rules:
      - alert: RedisMemoryHigh
        expr: redis_memory_used_bytes / redis_memory_max_bytes > 0.8
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Redis used_memory가 maxmemory의 80%를 초과했습니다"

이 알람 하나면 한계 도달 전에 증설·정리 시간을 벌 수 있습니다.

용량 산정 팁. 운영 데이터 기준 used_memory_rss에 fork/COW 여유로 1.3~1.5배를 곱해 maxmemory와 서버 RAM을 잡으세요. RDB를 쓴다면 더 보수적으로.

Redis 7.x에서는 maxmemory-clients로 클라이언트 버퍼까지 제한할 수 있고, 빈도 기반 allkeys-lfu 채택이 늘고 있습니다. 참고로 2024~2025년 라이선스 변경(RSAL→AGPL) 이후 Valkey로 옮기는 흐름도 있지만, maxmemory 동작과 명령은 동일하니 이 가이드를 그대로 적용할 수 있습니다.

자주 묻는 질문 (FAQ)

Q. CONFIG SET maxmemory-policy를 바꾸면 데이터가 즉시 삭제되나요? A. 정책을 evict 계열로 바꾸고 used_memory가 maxmemory를 초과한 상태라면, 초과분만큼 키가 즉시 제거됩니다. TTL 없는 영속 데이터가 있다면 allkeys-* 대신 volatile-*를 쓰거나 maxmemory를 먼저 늘리세요.

Q. CONFIG SET으로 바꿨는데 재시작하면 원래대로 돌아갑니다. A. CONFIG SET은 메모리상 설정만 바꿉니다. redis-cli CONFIG REWRITE로 redis.conf에 반영하거나, 설정 파일을 직접 수정해야 재시작 후에도 유지됩니다.

Q. used_memory는 여유가 있는데 OOM이 납니다. 왜죠? A. mem_fragmentation_ratio를 확인하세요. 1.5 이상이면 단편화로 RSS가 부풀어 OS 메모리가 부족한 상태입니다. activedefrag yes를 켜거나, 영속화 후 재시작으로 RSS를 회수하면 해결됩니다.

✦ ✦ ✦
편집 검토 · Editorial Review

이 글은 AI 에이전트가 1차 초안을 작성한 뒤, 사람 편집자가 사실관계·출처·톤과 맥락을 검토하여 발행했습니다. 오류나 부정확한 내용이 확인되면 24시간 이내에 정정합니다.

작성 · Content Reviewer·검토 · 사람 편집자·발행 · 2026년 6월 19일

댓글

불러오는 중...