[Thread]
: 쓰레드의 개념에 대해서는 이전의 글 https://wiserloner.tistory.com/548나, 혹은 이후에 병렬 프로그래밍을 정리하며 적을 것입니다.
- 자바는 JVM을 사용하기에, 가장 단순한 형태의 프로그램도, 수개의 쓰레드로 이루어져 있습니다.
(내 프로그램 + JVM 자체 쓰레드)
(스레드 경합)
- 공유 자원에 대해서, 여러 스레드가 동시에 요구를 할 때 일어나는 현상으로, 서로 다른 쓰레드 간에 자원을 가져가기 위한 경합이 자주 발생합니다.
- 경합이 심해지면, 어느 쓰레드가 자원을 소유하지 못하고 멈춰버리는 '데드락'이 걸리기도 합니다.
- 경합은, 어느 자원에 있어서, 한 스레드가 그것을 사용함에 있어서 잠궈놓은 '락'에 대해, 다른 스레드가 기다리느라 생기는 현상이라 이해하시면 됩니다.
- 스레드 경합으로 인해 여러 문제가 일어날수 있으며, 이러한 문제를 해결하기 위하여, 스레드의 상태를 저장하고 나타내는 '스레드 덤프(Thread Dump)'를 분석합니다.
(스레드 동기화)
- 비동기적인 스레드간의 경합으로 일어나는 문제들을 해결하기 위해선, 각 스레드가 자주 공유하는 자원에 대해서 서로 순서를 가지고 사용하게 되는 스레드 동기화를 구현해줘야 합니다.
- 자바에서는 Monitor라는 것을 사용해서 이를 동기화합니다.
(Monitor)
- 자바 객체는 하나의 Monitor를 가집니다.
- 하나의 Monitor는, 하나의 스레드만 가질수 있습니다.
- 어느 한 스레드가, 해당 객체의 모니터를 가지고 있는 상태라면, 다른 스레드는 그 객체에 진입하지 못하고, 스레드가 모니터를 반납할 때까지, Wait Queue에 대기하고 있어야 합니다.
(스레드 상태)
- 스레드의 상태는 java.lang.Thread 클래스 내부에 State라는 이름을 가진 Enumerated Types(열거형)으로 선언되어 있습니다.
- NEW: 스레드가 생성되었지만 아직 실행되지 않은 상태
- RUNNABLE: 현재 CPU를 점유하고 작업을 수행 중인 상태. 운영체제의 자원 분배로 인해 WAITING 상태가 될 수도 있다.
- BLOCKED: Monitor를 획득하기 위해 다른 스레드가 락을 해제하기를 기다리는 상태
- WAITING: wait() 메서드, join() 메서드, park() 메서드 등를 이용해 대기하고 있는 상태
- TIMED_WAITING: sleep() 메서드, wait() 메서드, join() 메서드, park() 메서드 등을 이용해 대기하고 있는 상태. WAITING 상태와의 차이점은 메서드의 인수로 최대 대기 시간을 명시할 수 있어 외부적인 변화뿐만 아니라 시간에 의해서도 WAITING 상태가 해제될 수 있다는 것.
(스레드 종류)
- 데몬 스레드, 비데몬 스레드가 있습니다.
- Non-daemon Thread : static void main(String[] args)에서 나온 스레드는 비데몬 스레드입니다.
- Daemon Thread : GC와 같은 JVM 보조 기능들은 모두 데몬 스레드입니다.
- 데몬 스레드는 비데몬 스레드를 보조하는 역할을 하며, 다른 비데몬 스레드가 없다면 데몬 스레드는 동작을 중지합니다.
- main 메서드가 실행되는 스레드를 HotSpot VM에서는 VM Thread라고 부릅니다.
(스레드 덤프 획득하기)
- 자바로 만든 웹 어플리케이션 등이 늦게 동작한다면, 그 어플리케이션이 실행시키는 스레드의 상태를 살펴봐야 합니다.
- 바로 그러한 정보를 가진 것이 스레드 덤프입니다.
- 스레드 덤프의 획득은, 획득할 당시의 스레드 상태만 알 수 있기 때문에 스레드 상태 변화를 확인하려면 5초 정도의 간격으로 5~10회 정도 획득하는 것이 좋습니다.
- Jstack 사용하기 :
1. CMD 창에,
jps -v
명령어를 입력하여, 돌아가고 있는 JVM 어플리케이션의 PID를 찾습니다.
2. jps로 추출한 PID를 인수로 넣어 jstack을 실행하면 스레드 덤프를 획득합니다.
jstack 18812
- Java VisualVM 사용하기
: Java VisualVM은, 스레드 덤프를 확인할수 있는 GUI 프로그램입니다.
https://d2.naver.com/helloworld/10963
왼쪽 패널은 실행 중인 프로세스의 목록입니다. 이 목록에서 정보를 원하는 프로세스를 클릭한 다음 오른쪽 패널에서 Threads 탭을 선택하면 스레드의 정보를 실시간으로 확인할 수 있습니다. 스레드 덤프를 파일로 저장하려면 스레드 정보가 나타나는 화면 오른쪽 위의 Thread Dump 버튼을 클릭하면 됩니다.
- kill 명령어를 사용하는 방법
: Linux 환경에서는 kill 명령어로 스레드 덤프를 획득할 수 있습니다. kill 명령어의 인수로 사용할 PID는 ps -ef | grep java 명령어로 확인합니다.
[user@linux ~]$ ps -ef | grep java user 25780 1 0 11:23 pts/3 00:00:00 /home1/user/java/jdk1.6.0_24/bin/java -Djava.util.logging.config.file=/home1/user/java/apps/tomcat/conf/logging.properties -Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager -Dfile.encoding=UTF-8 -XX:PermSize=256m -XX:MaxPermSize=256m -Xms1024m -Xmx1024m -server -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/home1/user/java/apps/tomcat/logs -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseConcMarkSweepGC -Djava.endorsed.dirs=/home1/user/java/apps/tomcat/common/endorsed -classpath :/home1/user/java/apps/tomcat/bin/bootstrap.jar:/home1/user/java/apps/tomcat/bin/commons-logging-api.jar -Dcatalina.base=/home1/user/java/apps/tomcat -Dcatalina.home=/home1/user/java/apps/tomcat -Djava.io.tmpdir=/home1/user/java/apps/tomcat/temp org.apache.catalina.startup.Bootstrap start user 26335 25361 0 15:49 pts/3 00:00:00 grep java |
ps 명령어로 확인한 PID를 다음과 같이 kill 명령어의 인수인 -3(또는 -QUIT나 -SIGQUIT)과 함께 사용하여 스레드 덤프를 획득합니다.
[user@linux ~]$ kill -3 25780 |
//저는 아래 출처를 통해 공부중입니다.
본격적인 스레드 덤프 분석 관련해서는 추후 공부를 하고 실습하며 정리할 예정입니다.
//출처 : https://d2.naver.com/helloworld/10963
1. 들어가며
1-1. 스레드의 종류
- Daemon Thread
- 작업을 돕는 보조적인 역할을 수행하는 쓰레드 (GC 도 여기에 해당)
- 프로세스 종료시 데몬 쓰레드는 강제적으로 자동종료
- 언제든지 종료가 되어도 상관없는 작업 시에 사용 (그래서 주로 데몬쓰레드를 쓴다)
- Thread t = new Thread(); t.setDaemon(true); 로 설정가능
- Non-Daemon Thread
- 실제 주 작업을 하는 스레드
- 프로세스 종료시 논데몬 쓰레드가 살아있는 경우 종료 불가능 (가끔 톰캣을 종료했지만 안꺼져서 kill 해야되는 이유)
- 매우 중요한 데이터 처리시에 사용하는 것이 일반적
1-2. 스레드덤프를 추출해보면 좋은 상황
- 모든 시스템에 응답이 없을 때
- 사용자 수가 많지 않은데 CPU사용량이 높을때
- 특정어플리케이션 수행 시 응답이 없을때
- 간헐적으로 응답이 느릴때
- 서비스 실행시간이 길어질수록 응답시간이나 cpu 사용량이 늘어날떄 등등
1-3. 멀티스레드 프로그래밍을 안하는데?
java.lang.Thread 를 이용해서 직접 개발하지 않더라도 이미 프레임워크, WAS, 라이브러리에서 내부적으로 사용하고 있다.
만약 라이브러리에서 문제가 생긴다면?? 이럴때 스레드덤프를 쓸 줄 안다면 유용할 것이여~~
2. 스레드덤프 생성하기
- OS단에서
- 리눅스 : kill -3 [PID]
- 윈도우 : Ctrl + Break
- java단에서 (jps -v 로 java 프로세스 확인)
- jstack [PID] (jstack으로 반응이 없는 경우 –F 옵션)
- jcmd [PID] Thread.print (jdk7 이후 등장)
- jcmd [PID] help 로 명령어 확인 가능, 직관적임
- 이때 시간이 있다면 텀을 두고 3~4장을 떠두는게 좋다.
3. 스레드덤프를 읽어보자
- 스레드이름
- lang.Thread 클래스로 생성하면 'Thread-숫자' 형식으로 생성된다.
- DefaultThreadFactory 를 사용하면 pool-숫자-thread-숫자 형식으로 생성된다.
- 하지만 이런 디폴트이름들로 쓰레드가 가득하다면 덤프를 읽기가 매우 힘들다. 멀티스레드 프로그래밍을 직접할 경우, setName을 이용해서 직관적인 스레드명을 써주는게 좋다.
- 우선순위 : 스레드 우선순위 (스펙에서도 안중요하다고 함)
- 스레드 아이디
- 16진수
- tid : 자바레벨 쓰레드ID, 자바프로세스마다 1부터 시작. 겹칠수 있겠다.
- ThreadMXBean과 ThreadInfo 을 이용하여 정보 획득 가능
- nid : 네이티브 쓰레드ID, OS영역이고 유니크함
- ps 명령어를 이용해 cpu 사용율 등도 알 수 있음
- 스레드 상태
- runnable
- blocked
- deadlock
- wait
- 스레드 콜스택
4. 스레드덤프의 각종 도구
4-1. JVisualVM
jdk 설치할 때 같이 설치되므로, 환경변수가 잘 잡혀있다면 jvisualvm 이라고 치면 바로 뜬다.
4-2. TDA
- Thread Dump Analyzer
- 오래되고 jvm 별로 포맷이 달라 안읽히는 경우도 있음
4-3. fastThread 사이트
출처: https://sjh836.tistory.com/151 [빨간색코딩]
'WEB,WAS > TOMCAT' 카테고리의 다른 글
EJB란 무엇인가? (0) | 2023.07.06 |
---|---|
Tomcat 9 관리자 접속하기 및 사용하지 않는 이유 (0) | 2023.02.23 |
Apache 2.4.X 설치 및 실행 for Windows 11 (0) | 2022.12.08 |
apache virtual host 설정 (0) | 2022.03.30 |
AJP (0) | 2022.01.26 |
댓글