Java 트러블슈팅 가이드: OOM, 스레드풀, 런타임 압박을 어디부터 볼까
마지막 업데이트

Java 트러블슈팅 가이드: OOM, 스레드풀, 런타임 압박을 어디부터 볼까


Java 서비스가 부하 아래에서 흔들릴 때 중요한 건 JVM 옵션 하나를 찾는 일이 아니라, 지금 보고 있는 문제가 진짜 메모리 압박인지, queue backlog인지, thread contention인지, 아니면 crash 전에 이미 런타임이 포화된 상태인지를 구분하는 일입니다.

짧게 말하면, 익숙한 JVM 튜닝부터 들어가지 말고 가장 먼저 눈에 띄는 병목부터 봐야 합니다. 그리고 그 증상과 가장 잘 맞는 좁은 가이드로 들어가는 것이 더 빠릅니다.

이 글은 이 블로그의 Java 트러블슈팅 허브 역할을 합니다.


처음 보이는 병목부터 찾기

처음에는 이런 질문이 유용합니다.

  • OutOfMemoryError가 보이는가
  • thread pool queue가 계속 증가하는가
  • GC pause가 갑자기 길어졌는가
  • CPU는 뜨거운데 throughput은 떨어지는가
  • thread dump에서 blocked progress나 deadlock이 보이는가
  • 서비스가 완전히 죽기 전에 이미 saturation 상태인가

이렇게 시작해야 backlog가 문제인데 heap만 늘리거나, 메모리 영역 압박이 원인인데 executor 설정만 만지는 실수를 줄일 수 있습니다.

빠른 JVM triage용 명령 예시

첫 상태를 빨리 볼 때는 아래 명령만으로도 다음 분기를 고르기 좋습니다.

jcmd <pid> GC.heap_info
jcmd <pid> Thread.print
jcmd <pid> VM.native_memory summary

한 번의 명령으로 장애 전체를 해결하려는 게 아니라, 가장 강한 신호가 memory pressure인지, queue growth인지, hot thread인지, blocked progress인지를 나누려는 것입니다.

간단한 Java 분기 지도

가장 빠른 첫 분기는 이렇게 보면 됩니다.

  • OOM variant, retained object, 메모리 영역 압박: OOM 글부터
  • queue 증가, busy worker, saturation: thread-pool backlog 글부터
  • pause spike, allocation churn, retained heap: GC pause 글부터
  • hot thread, retry loop, contention, wasted work: JVM CPU 글부터
  • lock 대기, waiting cycle, forward progress 정지: deadlock 글부터

이 지도는 의도적으로 단순합니다. 세 갈래를 반쯤 보는 것보다, 강한 한 갈래를 정확히 잡는 편이 낫습니다.

메모리 압박처럼 보일 때

다음 증상이면 Java OutOfMemoryError부터 보세요.

  • heap, metaspace, native pressure가 보인다
  • OOM variant 자체가 중요하다
  • 큰 collection, cache, retained payload가 의심된다
  • class metadata 증가가 이상하다

retained object의 정체가 아직 모호하다면 Java Heap Dump로 이어가면 좋습니다.

queue backlog 또는 executor saturation처럼 보일 때

다음 증상이면 Java Thread Pool Queue Keeps Growing부터 보세요.

  • executor queue가 계속 증가한다
  • worker가 계속 바쁘거나 blocked 상태다
  • 메모리보다 backlog가 더 먼저 눈에 띈다

인접한 분기로는 아래 글이 이어집니다.

긴 GC pause 또는 retained heap처럼 보일 때

다음 증상이면 Java GC Pauses Too Long부터 보세요.

  • 명확한 crash보다 pause spike가 먼저 보인다
  • 트래픽이나 payload 변화 뒤 allocation churn이 커졌다
  • old generation 증가가 의심된다

pause보다 retained object 증거가 더 필요하다면 다음은 Java Heap Dump가 맞습니다.

hot CPU 또는 contention처럼 보일 때

다음 증상이면 Java JVM CPU High부터 보세요.

  • CPU는 계속 높은데 throughput이 떨어진다
  • host metric보다 hot thread가 더 중요해 보인다
  • retry, spinning, contention, wasted work가 의심된다

특히 lock contention이 강하게 보이면 Java Thread Contention High로 이어가면 됩니다.

진행 정지처럼 보일 때

서비스가 단순히 느린 것이 아니라 멈춘 것 같다면 Java Thread Deadlock부터 보는 편이 좋습니다.

이 분기는 이런 상황과 잘 맞습니다.

  • thread dump에 waiting cycle이 보인다
  • throughput보다 lock ownership이 더 중요하다
  • 서비스가 forward progress를 거의 못 만든다

실전 조사 순서

어느 분기로 들어가야 할지 애매하면 아래 순서를 따르면 됩니다.

  1. 가장 먼저 보이는 병목을 찾습니다
  2. 시스템이 crashing인지, stalling인지, saturating인지 구분합니다
  3. memory-area pressure와 backlog pressure를 나눕니다
  4. hot CPU contention과 blocked-progress deadlock을 나눕니다
  5. 가장 강한 증상에 맞는 좁은 가이드로 이동합니다

이 순서가 잘못된 레이어를 먼저 튜닝하는 일을 줄여줍니다.

FAQ

Q. 이 글은 JVM 튜닝 가이드인가요?

아니요. 증상 기준으로 다음 분기를 고르는 허브 글입니다.

Q. queue 증가와 메모리 압박이 같이 보이면 어디부터 볼까요?

먼저 나타난 증상부터 보세요. 그리고 바로 이어지는 인접 가이드를 비교하면 됩니다.

Q. OOM은 없는데 GC pause만 심해졌다면 메모리 문제는 아닌가요?

그래도 메모리 압박 분기로 보는 것이 맞습니다. GC pause부터 보고, 필요하면 heap dump 분석으로 넘어가면 됩니다.

Q. CPU보다 deadlock을 먼저 봐야 하는 시점은 언제인가요?

forward progress가 멈추고, thread dump가 단순 hot loop보다 waiting cycle을 가리킬 때입니다.

먼저 읽어볼 가이드

검색 유입이 많은 핵심 글부터 이어서 보세요.