일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |
- 파이썬
- Proxy
- redis
- JavaScript
- JPA
- Algorithm
- Kafka
- IT
- 운영체제
- OS
- 자바
- Spring
- 알고리즘
- 자료구조
- 컴퓨터구조
- C
- MySQL
- 디자인 패턴
- mongoDB
- spring webflux
- MSA
- design pattern
- 네트워크
- react
- c언어
- Galera Cluster
- Java
- Heap
- Data Structure
- 백준
- Today
- Total
시냅스
Java 코드와 예제로 보는 Thread Dump 활용 방법 본문
Thread Dump
thread dump 를 활용하는 상황은 여러가지가 있을 수 있습니다.
JVM이 정상적으로 작동하는데 애플리케이션이 비정상적으로 느리다거나,
액티브 트랜잭션이 쌓이기만 하는데 메모리나 CPU가 이상현상이 없다거나,
정상 작동하면서 특정 환경에서는 TCP 에러가 발생한다거나 하는 등의 상황이 될 것입니다.
이전에 살펴보았던 Heap Dump 에서도 눈으로 확인하는 것이 중요하다는 것을 배웠습니다.
이번에는 Thread Dump 를 통해서 Thread 상태에 대해 확인하는 방법을 배워보겠습니다.
https://liltdevs.tistory.com/167
Thread 의 상태
- NEW
- 스레드가 생성되었지만 아직 실행되지 않은 상태
- RUNNABLE
- 현재 CPU를 점유하고 작업을 수행 중인 상태. 운영체제의 자원 분배로 인한 WATING 상태가 될 수도 있다.
- BLOCKED
- Monitor 를 획득하기 위해 다른 스레드가 락을 해제하기를 기다리는 상태
- WAITING
- wait(), join(), park() 메서드 등을 이용해 대기하고 있는 상태
- TIMED_WAITING
- WAITING가 다른 점은 시간을 지정해 줄 수 있어 외부 상태 뿐만 아니라 시간에 의해서도 풀릴 수 있음
언제 Thread Dump를 해야할까?
- CPU 사용량이 비정상 적으로 높을 때
- CPU를 가장 많이 점유하는 스레드가 무엇인지 찾아본다.
- 수행 성능이 비정상적으로 느릴 때
- BLOCKED 상태인 스레드 목록을 찾고 BLOCKED 상태인 스레드가 획득하려는 락과 관계된 스레드를 추출한다.
Thread Dump 이후 확인할 수 있는 경우들
- 락을 획득하지 못하는 경우 (Blocked)
- 한 스레드가 락을 소유하고 있어 다른 스레드가 락을 획득하지 못해 애플리케이션의 전체적인 성능이 느려지는 경우
- 데드락 상태인 경우
- 스레드 A가 작업을 계속하려면 스레드 B가 소유한 락을 획득해야 하고, 스레드 B가 작업을 계속하려면 스레드 A가 소유한 락을 획득해야 해서 데드락 상태에 있는 경우 (순환 대기)
- WAIT 상태에 있는 경우
- 스레드가 계속 WAIT 상태를 유지하고 있는 경우
- 스레드 리소스를 정상적으로 정리하지 못하는 경우
- 메인 스레드가 먼저 끝나고 join 으로 자원 처리 못한 경우
- 불필요한 스레드가 계속해서 늘어나는 경우
- 스레드 리소스를 정상적으로 정리 못하고 있는 경우이기 때문에 각 스레드를 정리하는 모습 혹은 스레드가 종료되는 조건을 확인하는 것이 좋다.
위의 예시들은 Thread Dump 를 실제로 보면서 확인하는 데에 용이합니다.
아래에서 실제로 확인해보도록 하겠습니다.
예제
@Service
class SynchService {
public void test() {
Thread.currentThread().setName("thread-dump-test"); // thread dump 내에서 구분을 위해 이름 지정
synchronized (this) {
try {
Thread.sleep(100000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
@RestController
class TestController {
@Autowired SynchService synchService;
@GetMapping("/")
public String threadDumpTest(HttpServletResponse response) {
synchService.test();
return "test";
}
}
이번 예제는 액티브 트랜잭션이 쌓이기만 하는 상황으로 가정하겠습니다.
실행 순서는 다음과 같습니다.
- HTTP Request를 JMeter 를 사용하여 3번 보냅니다.
- 이때 처음으로 들어온 Request(Thread) 는 lock을 획득하여 장시간 sleep 합니다.
- 다음으로 들어온 2번 3번 Request(Thread) 는 lock 을 획득하기 위해 대기합니다.
위의 상황을 VisualVM, JMeter 로 실행하여 확인해보겠습니다.
JMeter 로 3개의 Request를 보낸 결과서입니다.
처리량이 36개 / 1시간 이므로 아주 느리다는 판단을 먼저 할 수 있습니다.
이후 확인한 VisualVM Monitor 입니다.
아무런 문제가 없어 보입니다.
스레드를 확인하여 보니 뭔가 이상합니다.
1번 스레드가 장시간 sleep 에 들어가있고, 2번 3번이 monitoring 되고 있지만
장시간 어떤 수행도 하지 않습니다.
이때 Thread Dump 를 실행합니다.
위와 같은 thread 상태 들을 얻을 수 있습니다.
하나의 Thread 가 sleep 에 들어가있고 2개의 Thread가 Blocked 되어있습니다.
고로 우리는 '하나의 스레드가 sleep 에 들어가 2개가 영향을 받았구나.' 라고 추론해 볼 수 있겠습니다.
'Java, Spring' 카테고리의 다른 글
Spring 예제로 보는 중복 Request 방지, GUID (≒ UUID) (0) | 2023.03.02 |
---|---|
Java 코드로 보는 Connection 관련 timeout 에러 정리 (0) | 2023.03.01 |
Java 코드로 알아보는 직렬화와 역직렬화 (0) | 2023.02.28 |
Visual VM과 nGrinder를 사용한 모니터링과 부하 테스트 (0) | 2023.02.19 |
nGrinder 설명과 사용법 정리 (5) | 2023.02.19 |