이 문서를 통해 아래 질문들에 답할 수 있게 됩니다.
Thread Dump로 병목 읽기에서 붙잡아야 할 핵심 판단 기준은 무엇인가?thread state와 stack trace는 시간축으로 읽는다라는 기준은 어떤 JVM/OS 신호로 확인되는가?- Java/Spring 코드에서
Thread Dump로 병목 읽기판단 기준은 어떤 장애 신호로 드러나는가?
개요
이 문서의 주제는 Thread Dump로 병목 읽기이다. Thread state, stack trace, lock owner, 반복 샘플을 읽어 병목을 판단하는 방법을 다룬다.
먼저 붙잡을 기준은 다음 문장이다. thread state와 stack trace는 시간축으로 읽는다. 이 문서는 이 기준을 Java/Spring 실행 흐름, JVM/OS 관찰 지표, 장애 판단 순서로 연결한다.
핵심 모델
- 판단 기준: thread dump는 한 시점의 실행 위치 증거다.
- Thread state 이름만으로 원인을 확정하면 위험하다. 같은 stack이 반복되는지 봐야 한다.
RUNNABLE은 CPU 실행뿐 아니라 native I/O 대기까지 포함할 수 있다.BLOCKED는 monitor owner와 waiters를 함께 봐야 의미가 있다.- 2~3회 반복 dump를 같은 간격으로 남기면 일시 상태와 고착 상태를 구분할 수 있다.
문서별 핵심 구분
- thread dump는 Java thread의 state와 stack trace snapshot이다.
- 한 장보다 여러 장에서 반복되는 stack이 병목 증거로 강하다.
- BLOCKED, WAITING, RUNNABLE은 OS CPU 사용량과 함께 해석해야 한다.
원리
Thread dump는 “어떤 Java 코드 위치에 thread가 머물러 있는가”를 보여 준다. 그래서 CPU 사용률, latency, pool 지표와 연결할 때 강력하다. 하지만 dump 자체는 CPU 사용량, disk wait, network retransmit을 직접 측정하지 않는다.
먼저 thread name 분포를 본다. http-nio-*, task-*, scheduler-*, HikariPool-*, reactor-*처럼 이름이 나뉘면 어느 executor나 처리 모델에 thread가 몰렸는지 빠르게 좁힐 수 있다.
다음으로 state보다 stack의 반복을 본다. 많은 thread가 같은 DB 호출, 같은 lock, 같은 외부 API client, 같은 queue wait에 머물면 그 위치가 병목 후보가 된다.
Thread Dump로 병목 읽기 관점에서 중요한 점은 dump를 시간축으로 읽는 것이다. 단일 snapshot은 우연일 수 있으므로 여러 번 수집하고, 같은 시각의 top -H, GC log, pool metric과 맞춘다.
Java/Spring 연결
- Tomcat worker stack은 Controller, Filter, DB client, HTTP client 대기 위치를 보여 준다.
- Hikari, scheduler, async executor thread name은 병목 pool을 구분하는 1차 단서다.
- Lock owner와 waiting thread를 보면 synchronized 경합과 deadlock 후보를 좁힐 수 있다.
- CPU 급등 시에는 thread dump만 보지 말고
top -H의 TID와nid를 연결한다. - Thread dump 수집 시각을 access log, GC log, Actuator metric과 맞춰야 한다.
코드와 설정 예시
"http-nio-8080-exec-42" #142 daemon prio=5 os_prio=0 tid=0x... nid=0x7f03 BLOCKED
java.lang.Thread.State: BLOCKED (on object monitor)
- waiting to lock <0x00000007123> owned by "http-nio-8080-exec-17"
at com.example.OrderService.placeOrder(OrderService.java:42)예시는 dump에서 읽어야 할 핵심 단서다. thread name, nid, state, lock owner, application stack frame을 보고 어떤 요청 처리 경로가 어떤 자원에서 멈췄는지 추적한다.
관찰 명령
jcmd <pid> Thread.print > dump1.txt
sleep 10; jcmd <pid> Thread.print > dump2.txt
grep -E 'BLOCKED|WAITING|RUNNABLE' dump1.txt | headThread Dump로 병목 읽기 관찰 명령은 결론이 아니라 가설 확인 도구다. 운영 중에는 반복 간격, 대상 PID, 수집 시각을 함께 남기고 출력이 큰 명령은 범위를 제한한다.
지표 해석
| 신호 | 먼저 의심할 것 | 다음 확인 |
|---|---|---|
| RUNNABLE thread가 core보다 많음 | CPU 경합 또는 native I/O 대기 | top -H, stack trace, load average |
| BLOCKED가 특정 lock에 몰림 | synchronized/monitor 경합 | lock owner와 기다리는 thread |
| WAITING/TIMED_WAITING이 pool에 몰림 | queue 대기, connection 대기, sleep/retry | executor, Hikari, timeout 지표 |
| thread 수가 계속 증가 | unbounded executor 또는 thread leak | thread name 분포와 생성 위치 |
Thread Dump로 병목 읽기에서는 핵심 신호와 보조 지표를 같은 시간축에서 맞춘다. 먼저 변한 신호와 뒤따라 포화된 신호를 분리해야 원인과 결과를 구분할 수 있다.
장애 상황에서 보는 순서
- 10초 간격으로 thread dump를 2~3회 남긴다.
- 같은 stack에 반복해서 몰리는 thread 그룹을 찾는다.
- RUNNABLE, BLOCKED, WAITING을 stack 내용과 함께 해석한다.
- lock owner, DB wait, HTTP client wait, pool wait를 분리한다.
- CPU 문제라면
top -HTID와nid를 맞춰 hot thread를 찾는다.
이 순서는 thread dump를 상태명 암기가 아니라 반복되는 실행 위치 증거로 읽기 위한 루틴이다.
실전 팁
- 10초 간격으로 2~3회 dump를 남긴다.
- 같은 stack에 몰린 thread 수를 먼저 본다.
- lock owner와 waiting thread를 같이 찾는다.
- CPU hot thread는 native id를 변환해 dump와 맞춘다.
- dump 파일명에 시각, host, pid를 넣는다.
주니어 팁
Thread Dump로 병목 읽기주제는 용어 암기보다 정상 상태와 장애 상태에서 어떤 증거가 달라지는지 연결해 익힌다.- 처음에는
Thread Dump로 병목 읽기를 재현 가능한 기본 명령과 Actuator 지표로 확인하는 습관부터 만든다. Thread Dump로 병목 읽기숫자는 크기 자체보다 평소 기준선에서 얼마나 벗어났는지로 판단한다.
시니어 팁
Thread Dump로 병목 읽기주제의 영향이 pool, queue, retry, timeout으로 번지는 경로를 설계 리뷰에 포함한다.Thread Dump로 병목 읽기runbook에는 실행 명령, 정상 범위, 해석 기준, 금지할 대응을 같이 둔다.Thread Dump로 병목 읽기판단이 container, LB, 다중 인스턴스 환경에서도 같은 의미인지 확인한다.
Guru급 팁
Thread Dump로 병목 읽기주제는 단일 snapshot보다 변화 방향이 중요하다. 같은 명령을 간격을 두고 실행해 상태가 증가, 유지, 회복 중 어디인지 본다.- 고급 도구는
Thread Dump로 병목 읽기가설을 좁힐 때만 사용하고 기본 지표와 모순되는지 먼저 확인한다. Thread Dump로 병목 읽기조치 후에는 CPU, memory, socket, disk, pool 중 다음 포화 지점이 어디로 이동했는지 확인한다.
위험 신호!
- thread dump 한 장으로 결론을 확정한다.
- RUNNABLE을 모두 CPU bound로 해석한다.
- WAITING thread가 많다는 이유만으로 장애라고 판단한다.
- dump 수집 전에 재시작한다.
- thread name이 없어 executor를 구분하지 못한다.
확인 질문
확인 질문
Thread Dump로 병목 읽기주제를 장애 중 확인할 때 Application 로그만으로 부족한 이유는 무엇인가?
- 로그는 코드 경로를 보여 주지만
Thread Dump로 병목 읽기의 JVM/OS 자원 상태, 대기 위치, 포화 방향은 별도 지표로 확인해야 하기 때문이다.Thread Dump로 병목 읽기관련 설정이나 pool 크기를 바꾸기 전에 확인할 것은 무엇인가?
- 먼저 변한 신호, 하위 자원 capacity, 변경이 완화인지 증폭인지 판단할 기준을
Thread Dump로 병목 읽기지표로 확인해야 한다.Thread Dump로 병목 읽기재발을 막기 위해 장애 기록에 무엇을 남겨야 하는가?
- 발생 시간, 영향 범위, 사용한 명령,
Thread Dump로 병목 읽기핵심 지표, 원인 판단, 완화 조치, 근본 수정, 남은 리스크를 남긴다.