📌 Tomcat이 무엇인지, WAS를 진단할 때 어떤 부분들을 확인해야 하는지 등은 강의를 통해 확인할 수 있어요.
이 포스팅에서는 Thread dump에 대해 이야기할게요
1. Thread dump
Thread dump를 통해 Thread가 무슨 일을 하는지 알 수 있어요.
A. Thread 덤프 생성
$ ps -ef | pgrep java
$ jstack [pid] > thread.dump
B. Thread 덤프 내용
# 생성 시간 정보
2021-03-27 23:55:32
# JVM에 대한 정보
Full thread dump Java HotSpot(TM) 64-Bit Server VM (25.251-b08 mixed mode):
# DeadLock에 대한 정보
Found one Java-level deadlock:
=============================
"http-nio-8080-exec-6":
waiting to lock monitor 0x00007faa62973608 (object 0x00000005c0c4b1e8, a java.lang.Object),
which is held by "http-nio-8080-exec-5"
"http-nio-8080-exec-5":
waiting to lock monitor 0x00007faa60025508 (object 0x00000005c0c4b1f8, a java.lang.Object),
which is held by "http-nio-8080-exec-6"
Java stack information for the threads listed above:
===================================================
"http-nio-8080-exec-6":
at nextstep.subway.line.ui.LineController.findLockLeft(LineController.java:78)
- waiting to lock <0x00000005c0c4b1e8> (a java.lang.Object)
# Thread stack 정보
"http-nio-8080-exec-6" #47 daemon prio=5 os_prio=31 tid=0x00007faa6132c000 nid=0x7f03 waiting for monitor entry [0x0000700009bce000]
java.lang.Thread.State: BLOCKED (on object monitor)
at nextstep.subway.line.ui.LineController.findLockLeft(LineController.java:78)
- waiting to lock <0x00000005c0c4b1e8> (a java.lang.Object)
- locked <0x00000005c0c4b1f8> (a java.lang.Object)
완료 장면 설명. exec-6도 L1을 기다리면 순환 대기가 닫힙니다. L1=0x00000005c0c4b1e8 / L2=0x00000005c0c4b1f8. 원문 dump는 그대로 둡니다.
서로 점유한 락을 기다립니다. 어느 쪽도 자동으로 풀리지 않습니다.
L1: 0x00000005c0c4b1e8
L2: 0x00000005c0c4b1f8
exec-5/6: http-nio-8080-exec-5/6
단계별 장면
1. exec-5가 L1, exec-6가 L2를 점유합니다.
2. exec-5는 L1을 보유한 채 L2를 기다립니다.
3. exec-6도 L1을 기다리면 순환 대기가 닫힙니다. L1=0x00000005c0c4b1e8 / L2=0x00000005c0c4b1f8. 원문 dump는 그대로 둡니다.
Thread 이름, 식별자, 우선순위(prio), Thread가 점유하는 메모리 주소를 의미하는 Thread ID(tid), OS에서 관리하는 Thread ID (nid), Thread 상태 (NEW | RUNNABLE | BLOCKED | WAITING | TIMED_WAITING | TERMINATED) 등의 정보를 확인할 수 있어요.
C. 실습
저장소를 clone 받습니다.
$ cd docker && docker-compose up -d
a. 테스트
# 상황 1
$ curl localhost:8080/lines
# 상황 2
$ curl localhost:8080/lines/lock-left
$ curl localhost:8080/lines/lock-right
# 상황 3
여러 브라우저 혹은 터미널로 요청해본다.
$ curl localhost:8080/lines/tan
$ curl localhost:8080/lines/tan
...
b. Thread dump 로컬로 download
# 운영서버에서 Bastion으로 파일 옮기기
$ rsync -avzh [원격대상경로] [받을경로]
# 예)
$ rsync -avzh ubuntu@2.2.2.2:/home/ubuntu/log/ ./log/
# Bastion 서버에서 파일 다운로드
$ scp -i [pem키] ubuntu@1.1.1.1:/home/ubuntu/log/thread.dump .
2. Arthas 활용하기
A. Arthas 설치 및 실행
VisualVM을 사용해주셔도 좋습니다.
$ curl -O https://arthas.aliyun.com/arthas-boot.jar $ java -jar arthas-boot.jar
B. dashboard

쓰레드 상태, 메모리 그리고 시스템의 전반적인 상황을 확인할 수 있어요.
우선 CPU 사용량, 누적 시간이 많은 쓰레드를 확인해보세요
새로운 쓰레드를 계속 생성할 경우엔 쓰레드 풀을 사용해야 합니다
C. thread

$ thread --all
$ thread -b
RUNNABLE이 높을 경우 : 정상적인 상태이나, CPU 사용량이 비정상적으로 높을 경우 확인해봐야 합니다.
BLOCKED가 높을 경우 : Lock 상태의 쓰레드이므로 원인을 파악해봅니다.
WAITING / TIMED_WAITING : 문제되지 않아요.
D. trace
