이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.

  • Memory Pressure와 Swap에서 붙잡아야 할 핵심 판단 기준은 무엇인가?
  • memory 압박은 latency로 먼저 보일 수 있다라는 기준은 어떤 JVM/OS 신호로 확인되는가?
  • Java/Spring 코드에서 Memory Pressure와 Swap 판단 기준은 어떤 장애 신호로 드러나는가?

개요

이 문서의 주제는 Memory Pressure와 Swap이다. Memory pressure, page fault, swap, OOM kill이 Java 서버에 미치는 영향을 설명한다.

먼저 붙잡을 기준은 다음 문장이다. memory 압박은 latency로 먼저 보일 수 있다. Heap OOM이 나기 전에도 page fault, swap, GC 증가, cgroup pressure가 응답 지연과 CPU 상승으로 먼저 나타날 수 있다.

핵심 모델

  • 판단 기준: memory 압박은 latency로 먼저 보일 수 있다.
  • Memory pressure는 heap만의 문제가 아니라 RSS, native/direct memory, page cache, cgroup limit이 함께 압박받는 상태다.
  • Swap si/so가 움직이면 Java heap이 아직 살아 있어도 latency가 크게 흔들릴 수 있다.
  • Heap OOM, native OOM, OS/cgroup OOM kill은 증거와 조치가 다르다.
  • Cache, batch, export, upload처럼 메모리를 크게 잡는 기능은 backpressure와 상한이 필요하다.
  • Memory 증설은 완화책일 수 있지만 leak, unbounded cache, batch 적재 문제를 대신 해결하지 못한다.

문서별 핵심 구분

  • memory pressure는 GC 증가, page fault, swap, OOM kill로 나타난다.
  • swap은 서버 latency를 크게 흔드는 위험 신호다.
  • heap과 RSS, cgroup limit을 분리해서 본다.

원리

Memory pressure는 단순히 free memory가 낮다는 뜻이 아니다. JVM heap, native/direct memory, page cache, cgroup limit, swap 활동이 함께 압박을 받는 상태다.

Swap in/out이 발생하면 CPU가 계산 대신 memory page를 disk와 주고받는 데 시간을 쓰게 되어 latency가 크게 흔들릴 수 있다. Java 서버에서는 GC pause와 swap 지연이 겹치면 장애가 더 커진다.

Heap used가 높으면 GC와 heap dump를 보고, RSS가 높으면 native/direct/metaspace/thread stack을 본다. Container에서는 host memory보다 cgroup limit에 먼저 닿을 수 있다.

따라서 memory 장애는 heap, RSS, cgroup, swap, OOM kill log를 같은 시간대에 놓고 “어느 한계에 먼저 닿았는가”를 확인해야 한다.

Java/Spring 연결

  • Actuator heap metric은 JVM heap을 보여 주지만 RSS와 cgroup pressure를 대신하지 못한다.
  • Large response, batch export, cache, direct buffer, thread 증가가 memory pressure를 만들 수 있다.
  • GC pause가 늘면 request thread는 살아 있어도 latency가 튈 수 있다.
  • Container OOM kill은 Java OutOfMemoryError 없이 process 종료로 보일 수 있다.
  • Memory 완화는 유입 제한, batch 중지, cache 축소, heap dump 여부 판단으로 나눈다.

코드와 설정 예시

date -Is
free -h
vmstat 1 5
jcmd <pid> GC.heap_info
cat /proc/<pid>/status | grep -E 'VmRSS|VmSize|Threads'

예시는 OS memory, JVM heap, process 상태를 같은 시간에 모으는 흐름이다. Swap이 움직이는지, OS OOM kill이 있었는지, heap과 RSS 중 어느 쪽이 먼저 압박을 받는지 나눠야 한다.

관찰 명령

free -h
vmstat 1 5
dmesg | grep -i 'out of memory' | tail
jcmd <pid> GC.heap_info

Memory Pressure와 Swap 관찰 명령은 결론이 아니라 가설 확인 도구다. 운영 중에는 반복 간격, 대상 PID, 수집 시각을 함께 남기고 출력이 큰 명령은 범위를 제한한다.

지표 해석

신호먼저 의심할 것다음 확인
si/so 증가swap 활동vmstat, disk latency
Heap used 증가heap leak, allocation burstGC log, heap dump
RSS 증가, heap 안정native/direct/thread stackNMT, /proc
OOM kill logcgroup/OS limit 초과dmesg, container event

Memory 분석은 heap, RSS, swap si/so, cgroup event, GC pause의 순서를 맞추는 일이다. 어느 한계에 먼저 닿았는지에 따라 dump, 완화, limit 조정이 달라진다.

장애 상황에서 보는 순서

  1. Heap, RSS, cgroup memory, swap 활동을 같은 시각에 확인한다.
  2. Java OOM인지 OS/cgroup OOM kill인지 로그로 나눈다.
  3. Swap si/so, major fault, disk latency가 latency spike와 겹치는지 본다.
  4. Heap 문제면 histogram/dump, RSS 문제면 NMT/direct/thread/metaspace를 본다.
  5. 임시 완화와 근본 수정(cache 제한, leak 수정, limit 조정)을 분리한다.

이 순서는 heap과 process memory를 분리하기 위한 루틴이다. Java OOM이 보이지 않아도 OS/cgroup이 process를 죽였을 수 있으므로 JVM 로그와 kernel/container event를 함께 본다.

실전 팁

  • Swap이 움직이는 서버는 latency 관점에서 이미 위험 신호로 본다.
  • Heap과 RSS가 다르게 움직이면 heap 밖 memory를 별도로 추적한다.
  • Container에서는 host free보다 cgroup limit과 OOM event를 우선한다.
  • Memory 증설은 leak과 unbounded cache를 숨길 수 있어 근본 수정과 분리한다.
  • 장애 회고에는 heap/RSS/cgroup/swap/OOM log를 한 표로 남긴다.

주니어 팁

  • Free memory 숫자 하나로 판단하지 말고 heap, RSS, swap을 나눠 본다.
  • Java OOM과 OS OOM kill은 로그와 증상이 다르다.
  • Swap si/so가 움직이면 latency와 함께 확인한다.

시니어 팁

  • Cache, batch, export, upload 기능은 memory 예산과 backpressure를 설계에 포함한다.
  • Container memory limit은 heap과 native, page cache 여유를 함께 반영한다.
  • OOM 대응 runbook에는 dump 수집 여부, disk 여유, 민감 정보 처리를 포함한다.

Guru급 팁

  • 서비스별 memory budget은 heap, direct, metaspace, thread stack, page cache를 나눠 잡아야 container limit에 안전하게 들어간다.
  • OOM runbook은 dump를 뜰지 말지부터 결정해야 한다. dump가 필요한 증거인지, disk와 개인정보 위험을 감당할지 판단한다.
  • Memory 완화 후에는 cache hit ratio, GC pause, RSS, swap이 어떻게 바뀌었는지 같이 봐야 성능 손실을 평가할 수 있다.

위험 신호!

  • free의 available만 보고 Java memory 문제를 배제한다.
  • Heap만 키우고 RSS/cgroup limit을 확인하지 않는다.
  • Swap이 움직이는데 GC tuning만 반복한다.
  • OS OOM kill을 Java exception이 없다는 이유로 놓친다.
  • Heap dump를 남기기 전에 disk 여유와 민감 정보를 확인하지 않는다.

확인 질문

확인 질문

  • Heap OOM과 OS OOM kill을 구분해야 하는 이유는 무엇인가?
    • Heap OOM은 JVM 내부 한계이고 OS/cgroup OOM kill은 process 전체 memory limit 초과라 증거와 조치가 다르기 때문이다.
  • Swap이 Java 서버 latency를 흔드는 이유는 무엇인가?
    • Memory page를 disk와 주고받으며 application과 GC가 기다리는 시간이 커질 수 있기 때문이다.
  • Memory limit을 늘리기 전에 확인할 것은 무엇인가?
    • Heap/RSS/cgroup/swap/OOM log와 leak, cache, batch 적재 같은 증가 원인을 확인해야 한다.

참고 문서