[JVM] JMC, JFR - 기본적인 사용법

2021. 12. 16. 15:26 JAVA/JVM

(프로덕션 환경에서 사용할려면 라이센스 필요, 그외에는 무료로 사용 가능)
JMC 는 두 가지 주요 목적으로 사용될 수 있다
1) JVM의 상태를 모니터링
2) Java Flight Recorder를 이용해서 생성한 덤프 파일 분석
JMC, JFR을 통해 무엇을 할 수 있는지 살펴보자

※ 주의! 어플리케이션 성능
JFR을 이용해서 어플리케이션을 모니터링할 때는 성능을 주의해야한다. 
JFR을 이용해서 얻을 수 있는 데이터 종류가 많기 때문에, 모든 것을 측정하려고 하면 어플리케이션에 부하가 심해진다. 
따라서 원하는 데이터만 골라서 기록해야 한다. 
JFR은 데이터의 종류 뿐만 아니라 데이터를 얼마나 자주 측정할지 등 기본적인 설정이 필요하다.
JFR은 미리 설정된 프로파일을 제공한다. (default.jfc, profile.jfc)
==> jdk 설치 경로/ jre / lib / jfr / default.jfc, profile.jfc 

Object statistics, Allocations 기능이 그렇게 무겁나??
Object statistics, Allocations 기능은 Default로 해제되어 있고 Custom profile을 생성함으로써 사용할 수 있다
기능을 On / Off 하고 어플리케이션의 성능을 테스트해본 결과, 
기능을 끄고나서는 181 GC 중 1개의 Full GC 가 발생했고 기능을 키고 나서는 485 GC 중 104개의 Full GC가 발생했다고 한다. (물론 어플리케이션마다 다를 것이다.)
GC로 인한 중단시간도 20% 증가했다. 프러덕션 환경에서는 사용하지 말 것..

 
JMC : Java Mission Control

JMC - Realtime process monitoring
- JAVA 7u40이상 버전을 설치하면, CMD에서 아래와 같이 jmc만 입력하면 Java Mission Control을 실행할 수 있다.  
- "+" 버튼을 이용해서 자기가 보고자 하는 것을 볼 수 있다
- 수치들을 기록해주는 것을 "카운터" 라고 부른다. 

JMC - Event triggers
- JMC의 특정 카운터가 특정 경계값을 넘어서면 알람을 주도록 설정할 수 있다
        Ex. 일정 시간동안 CPU의 사용률이 높다면 메일을 보낸다
- 원하는 값을 이용해서 트리거를 만들 수도 있다. 
        Ex. 특정 캐시의 접근이 N번 이상이면 콘솔에 로그를 찍는다

알람을 주는 행동은 아래와 같이 이메일, 콘솔 로그 등 여러가지가 있지만, 그 중에서도 Java Flight Recording을 실행시킬 수 있다.
        Ex. CPU 사용률이 90%이상으로 5초동안 지속되면 그 때부터 JFR 을 30초간 실행시켜서 그 때의 상세한 정보를 *.jfr파일에 기록해 뒀다가, 나중에 JMC로 읽어서 분석할 수 있다.
- 이처럼 JFR은 상세하게 기록해주는 툴이고, 이를 분석하기 위해 JMC 로 읽어들일 수 있다.



JMC - Memory
- Full GC, 히스토그램 생성 버튼 모두 어플리케이션을 잠깐 멈추게 할 수 있으므로 실제 프로덕션에서는 주의해서 사용할 것
- 아래와 같이 분석을 위해 Full GC를 임의로 발생시켜서 힙을 정리할 수 있다
- 힙 정리 후, Refresh heap histogram버튼을 눌러서 힙에 있는 클래스들을 볼 수 있다.
  ==> 인스턴스가 몇 개 생성되었는지도 확인 가능!
  ==> 한 개만 생성되어야하는 싱글톤 인스턴스가 여러개 생성되었다든지, 오작동하는 것을 확인할 수 있음


JMC - Thread
스레드 탭에서는 아래와 같은 것들을 확인 가능
- 스레드 상태 (Running, Blocked, Waiting )
- 스레드 락 이름
- 스레드가 데드락에 걸렸는지 여부
- 스레드가 블락된 횟수
- 스레드마다 CPU 사용량
- 스레드가 시작된 후 스레드에게 할당된 총 메모리 양

 
JFR: Java Flight Recorder

JFR은 JMC의 기능중 하나이다
- 특정 기간동안 어플리케이션 상세정보를 기록하여 나중에 JMC에서 분석하도록 로그 파일을 남긴다.

JFR 설정하기
어플리케이션 실행 시, JVM 옵션에 아래와 가이 두 가지를 추가해줘야 한다
-XX:+UnlockCommercialFeatures
-XX:+FlightRecorder

JVM 은 Default로 Stack trace 정보를 출력할 때, 출력물이 있을 때 바로 출력하는 것이 아니라 JVM 이 안전하다고 판단되는 상황에서 출력한다. 때문에 실제로 출력된 스택 정보는 약간의 지연이 발생할 수 있다. JVM 이 지연없이 스택정보를 바로 출력하고 싶다면, 아래의 두가지 옵션을 추가해줘야 한다. 
-XX:+UnlockDiagnosticVMOptions
-XX:+DebugNonSafepoints


JFR 실행하기
$ jcmd {pid} JFR.start duration=60s filename=bong.jfr
==> {pid} 에 해당하는 어플리케이션을 앞으로 60초동안 기록한다. 기록은 bong.jfr파일로 남긴다.
(jcmd는 자바 관련 커맨드를 실행할 수 있는 툴, JMC과 마찬가지로 기본적으로 제공) 

1분의 시간이 지나면 아래와 같이 해당 위치에 기록 파일이 남겨진다

이제 JMC에서 해당 파일을 열면 된다.


JFR - Memory 
- 메모리 관련 상세 정보를 볼 수 있다
- 어떤 GC가 언제 몇초동안 발생했는지, GC로그 확인 가능
- 메모리 할당 정보, TLAB에 메모리가 할당되었는지의 여부
- 힙 스냅샷 정보 ( 어떤 클래스가 얼마나 로딩되었는지 )
- 파란색 Used Heap사용되는 힙 크기로, 아래의 올라갔다 내려오는 것을 반복하는 패턴은 Minor GC가 발생함에 따라 나타나는 패턴이다. 



JFR - Allocation by Class
- 어떤 클래스의 인스턴스가 얼만큼 할당되었는지 확인 가능
- 쓸모없는 인스턴스들이 생성되는 것을 확인하고 어플리케이션 코드를 튜닝해야됨.

http://java-performance.info/over-32g-heap-java#hints

 

JFR - Allocation by Thread
- 특정 스레드가 생성하는 인스턴스들을 확인할 수 있다. 


JFR - Allocation Profile
- 하나의 스레드에서 사용하는 메모리 할당 정보를 상세하게 볼 수 있다
- Pressure : 어떤 클래스의 인스턴스 또는 메소드가 메모리 내의 공간을 가장 많이 차지하는지 알 수 있다. 메소드 콜이 너무 많을 경우 캐시를 적용하는 등의 어플리케이션 코드를 튜닝해야 한다.
( ※ Allocation은 기본적으로 Off되어있어서 해당 정보를 볼 수 없는데, 해당 기능을 켜는 방법은 나중에 알아보기...)


JFR - Code
- 어플리케이션 소스코드의 어떤부분에서 CPU 를 가장많이 차지하는지 확인할 수 있다
- Hot mehod : 어떤 메소드가 CPU 를 가장많이 사용하는지 확인 가능
- Sample Count : 메소드의 호출 횟수를 전부다 카운트 하면 좋겠지만, 그럴 경우 부하가 너무 심하다. 일정 주기마다 카운트를 센다. 전부 샘플링을 통한 통계값이기 때문에 정확한 값이 되지 못한다. 


JFR - Exceptions
- 기록하는 동안 발생한 예외들을 확인 가능

JFR - Threads
- 스레드 개수
- 스레드 당 CPU 사용 프로파일
- 스레드 블락킹 정보
- 지연 정보 (Waiting)
- 락 정보

JFR - I/O
- 예상치 못한 I/O가 발생하는가?
- SSD를 사용할 경우 File Read Threshold를 1ms 로 줄여야 한다. 디폴트는 10ms인데 SSD는 너무 빨라서 그렇지 않으면 너무 많은 I/O 정보를 놓칠 것이다. 
- Sampling 된 값이기 때문에, 마찬가지로 정확한 값은 아니다. 몇초 마다 한번씩 샘플링을 하기 때문에 특정 시간에 발생한 I/O는 누락될 수 있다.