본문 바로가기
DevOps

VisualVM을 통한 원격 서버 도커 내 JVM 성능 모니터링

by devLog by Ronnie's 2023. 3. 4.

메모리 관련 이슈가 발생하여 (java.lang.OutOfMemoryError: Java heap space) 원인 분석을 위해 VisualVM을 사용하였고 해당 내용을 정리한다. OutOfMemoryError: Java heap space 가 발생한다면 힙 메모리의 사이즈를 늘리면 해결은 할 수 있겠지만 근본적인 원인을 해결하는 것은 아니기에 해당 방법은 추천하지 않는다.

 

OOME 발생 시 메모리 관련 분석 툴 중에서는 VisualVM / Jmap / Eclipse Memory Analyzer 등이 있는데 그 중에서도  JVM을 실시간으로 모니터링을 할 수 있고 heap 덤프도 제공하는 툴인 VisualVM을 사용하기로 했다.

 

기본적으로 로컬 환경에서 분석하는 방법은 해당 툴이 알아서 인식하기에 따로 설정은 필요없어 편리하게 이용할 수 있지만 원격 서버에 경우에는 설정해줘야 하는 값들이 있다. 추가적으로 원격 서버 내에서 자바 애플리케이션이 도커 컨테이너에서 동작한다면 더더욱 해당 글이 도움이 될 것이다.

 

VisualVM을 통한 원격 서버 도커 내 JVM 성능 모니터링

 

VisualVM을 통한 원격 서버 도커 내 JVM 성능 모니터링

 

VisualVM 이란?


VIsualVM의 공식문서에서는 ‘올인원 JAVA 문제 해결 도구’라고 VisualVM을 소개한다.

 

이 소개 한줄에서 알 수 있듯이 VisualVM은 JVM을 실시간으로 모니터링 할 수 있는 오픈소스 기반 GUI툴이다. 위에서도 말했듯이 heap덤프를 제공하며 쓰레드덤프도 제공한다.

 

주로 메모리 관련 이슈가 발생할 경우 사용하며 heap 덤프를 사용해 메모리 분석을 할 때 사용된다. (Jmap을 통해서도 힙 덤프 파일을 생성 할수도 있다.) JDK6부터 지원을 한다.

 

VisualVM 기능


VisualVM은 아래와 같이 여러 기능들을 제공한다.

 

  • 로컬 및 원격 Java 프로세스 표시
  • 디스플레이 프로세스 구성 및 환경
  • 프로세스 성능 및 메모리 모니터링
  • 프로세스 스레드 시각화
  • 프로필 성능 및 메모리 사용량
  • 스레드 덤프 가져오기 및 표시
  • 힙 덤프 가져오기 및 찾아보기
  • 코어 덤프 분석
  • 오프라인에서 애플리케이션 분석

조금 더 자세한 설명은 VisualVM 공식 문서의 정리가 너무 잘되어 있어 공식 문서로 대체한다. (이미지 캡쳐본과 같이 정리가 되어 있다.)

https://visualvm.github.io/features.html

 

VisualVM: Features

Features VisualVM monitors and troubleshoots applications running on Java 1.4+ from many vendors using various technologies including jvmstat, JMX, Serviceability Agent (SA) and Attach API. VisualVM perfectly fits all the requirements of application develo

visualvm.github.io

 

 

VisualVM을 통한 원격 서버 도커 내 JVM 성능 모니터링 방법


먼저 설치를 위해 VisualVM 사이트에 접속하여 다운을 받아준다.

https://visualvm.github.io/index.html

 

VisualVM: Home

News: October 18, 2022: VisualVM 2.1.5 Released This release adds support for JDK 19 and delivers many improvements and bugfixes. See the Release Notes for all changes. The tool can be downloaded from the Download page, sources are available in release215

visualvm.github.io

 

설치 완료 후 VisualVM을 실행하면 다음과 같은 화면이 나온다.

원격 접속 설정에 앞서 먼저 왼쪽 탭에 Applications 항목에서 로컬 및 원격에 Java 프로세스를 확인할 수 있다는 점을 확인하자.

 

공식문서에서도 다음과 같이 설명을 해주고 있다.

 

Local을 눌러보면 다음과 같이 현재 나의 로컬에서 돌아가고 있는 Java 프로세스를 확인할 수 있고 해당 사항은 따로 설정해주는 것이 아닌 VisualVM 자체에서 자동으로 등록하여 보여준다.

 

반면 Remote에 경우에는 설정을 해줘야 하므로 당연히 아무것도 없다.

 

그럼 이제 원격 서버에 대한 Java 애플리케이션 연결해보자.

 

먼저 왼쪽 탭에 존재하는 Remote에 우클릭을 누른 후 Add Remote Host를 누른다.

 

그러면 해당 창이 나오게 되는데 여기서 Host name에 원격 서버의 IP를 넣어준다.

 

추가적으로 Display name를 설정하여 다음과 같이 이름으로 표시가 된다.

 

이제 생성된 원격 서버의 모니터링을 할 수 있도록 연동이 필요하다. 우클릭을 눌러 Add JMX Connection을 눌러준다.

 

여기서 나오는 JMX란 Java Management Extensions의 약자로 JVM 애플리케이션의 관리 및 모니터링을 위한 표준 API이다.

 

JVM에는 JMX가 모니터링을 할 수 있도록 내장 계측이 설정되어 있어 JMX를 통해 메모리를 모니터링 할 수 있는 것이여 VisualVM 툴은 이러한 모니터링 결과값을 GUI 환경에서 볼 수 있도록 도와주는 도구인 것이다.

 

Add JMX Connection을 누르게 되면 다음과 같이 처음 생성할 때 작성했던 IP가 나온다. IP 옆에 JMX 연결을 위한 포트번호를 적은 후 ok를 눌러 생성해준다.

 

설정을 해주면 다음과 같이 Not suppoted for this JVM. 이라는 문구가 나오면서 아직 연결이 안된 것을 알 수 있다. 추가적으로 Java 애플리케이션을 실행할 때 추가작업이 필요하다.

 

추가적으로 JMX 구성 매개변수를 추가해줘야 하는데 삽질을 좀 했다.

 

자바 실행 시 다음과 같이 설정들을 추가해서 실행해주도록 하면 된다. (Dockerfile 내 추가)

java \
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.local.only=false \
-Dcom.sun.management.jmxremote.port=[JMX PORT 설정] \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
-Djava.rmi.server.hostname=[붙을 서버 IP] \
-Dcom.sun.management.jmxremote.rmi.port=[JMX PORT 설정]

 

일반적으로 원격 서버 내 Java app이 실행될 때는 다음과 같이 설정만 해주면 바로 잘 연동이 된다.

 

하지만 필자의 환경에서는 Java app이 도커 컨테이너 안에서 동작을 하고 있었기 때문에 추가적으로 설정이 필요했다.

 

여기서 추가 설정이란 바로 도커 컨테이너에서 포트를 열어줘야 한다. ssh를 통해 해당 서버의 접속 후 도커 컨테이너의 포트를 확인해준다. (docker ps or docker ps -a)

 

다음과 같이 9003번 포트만 설정이 되어 있다. (포트는 설정마다 다를 수 있음)

 

이 상태에서 9003번을 JMX 포트 설정에 넣게 되면 해당 컨테이너에서 작동하고 있는 java app이 먹통이 되게 된다.

 

필자의 경우는 docker-compose를 통해 docker container를 실행하였으므로 docker-compose.yml 파일 내에 포트 설정에 추가적으로 jmx에 사용할 포트를 설정하였다. (ports 부분에 추가 작성)

 

이후 docker ps로  다시 확인해보면 다음과 같이 추가된 것을 확인할 수 있다.

 

그렇다면 다시 VisualVM으로 돌아가보면 다음과 같이 해당 app이 잘 연동된 것을 확인할 수 있으며 아이콘도 활성화가 되어 있다.

 

해당 자바 프로세스를 클릭해보면 다음과 같이 연동된 프로세스의 여러 정보(PID/host/jvm/java version 등..)들을 확인 할 수 있다.

그리고 가운데 상단을 보면 다음과 같은 탭들을 확인 할 수 있다.

 

각각의 탭들을 기본적으로 제공하는 기능이며 기능들의 정보는 다음과 같다.

  • Overview : 사용 옵션 및 java version과 같은 시스템 정보를 확인할 수 있음
  • Monitor : CPU, Memory, Classes, Threads 등을 볼 수 있음
  • Threads : 지금 Thread의 상태를 확인할 수 있음
  • Sampler : CPU, Memory 샘플링 할 수 있음

 

 

이외에도 상단의 Tools -> Plugins에서 제공하는 플러그인 다운을 통해서 여러 기능들을 제공받을 수 있다.

 

끝에 있는 VisualGC에 경우 플러그인을 통해 설치한 것이다.

 

자 이제 Monitor 탭을 눌러 들어가보면 다음과 같이 여러 정보들의 실시간 그래프들을 볼 수 있다. 여기서 볼것은 상단의 Cpu 그래프와 Heap 그래프이다.

 

 

그리고 여기서 Heap Dump 파일을 얻을 수 있는 기능이 있다.

 

Heap Dump를 누르게 되면 다음과 같이 hprof 파일을 저장할 수 있으며, 해당 파일은 원격 서버내 경로에 저장이 된다.

 

여기서 추가적으로 Docker를 사용하여 app을 띄운 경우에는 경로가 다르니 find 명령어를 통해 해당 파일을 찾아서 다운 받으면 된다.

 

이렇게 다운받은 heap dump 파일은 Eclipse Memory Analyzer(이하 MAT)를 통해서 다음과 같이 분석이 가능하다.

 

해당 글은 VisualVM에 관한 내용 글이므로 MAT에 관련된 사항은 추후 정리하여 게시하도록 한다.

 

부하테스트를 통한 VisualVM 모니터링


마지막으로 이렇게 연동을 마친 후 부하테스트(Stress Test)를 진행을 해보면서 모니터링을 해야 되는데 이때 사용할 수 있는 유명한 툴로는 JMeter / K6 / nGrinder 가 있다.

 

JMeter 경우에는 이전에 정리한 글이 있으니 아래 글을 참조하여 테스트를 진행해 본다

JMeter를 이용한 부하테스트 및 설정 방법

 

JMeter 를 이용한 API 성능 테스트

API 성능 테스트가 필요할 때 사용할 수 있는 여러 툴 중에서 JMeter를 이용한 테스트 방법에 대해서 정리한다. JMeter에 대한 기본 개념과 설치 방법 및 테스트 방법에 대해서 알아보자. JMeter 를 이

sjparkk-dev1og.tistory.com

추가적으로 k6를 이용한 부하 테스트 방법도 참고하길 바란다.

k6를 이용한 부하테스트 방법

 

k6를 이용한 부하테스트 방법

k6는 Grafana Labs에서 만든 부하 테스트 툴로 API 엔드포인트에 대한 성능 테스트 도구로 사용되며 오픈소스이다. 부하테스트 및 테스트 시나리오를 자바스크립트 코드 기반으로 작성하여 재사용성

sjparkk-dev1og.tistory.com

 

JMeter를 통해 설정을 마친 후 부하테스트를 진행 후 VisualVM 그래프를 봐보면 CPU 그래프와 Heap 그래프의 변화를 볼 수 있다.

거의 실시간으로 그래프의 변화를 확인할 수 있다.

 

JMeter로 API 부하 테스트 진행 시 급격히 CPU 사용률이 올라가는 것과 GC activuty 사용량이 올라가는 것을 확인 할 수 있다. 그리고 힙 메모리 사용 그래프에도 변화를 확인할 수 있다.

 

이전 서버에서는 힙메모리 설정을 -Xms512m -Xmx512m로 주어진 서버였고, 다음 서버는 -Xms2048m -Xmx4096m로 주어진 서버에서의 테스트 결과이다.

 

-Xms 값을 2기가로 주었기 때문에 힙의 사이즈가 2기가였다가 사용되는 힙 메모리가 늘어남에따라 증가했다가 일정 시간 지난 후 다시 2기가로 돌아오는 것을 확인할 수 있다. (Xms 값은 최소 값이 아닌 힙의 초기 크기이다.)

이렇게 힙 사이즈가 늘어날 수 있는 것은 Xmx 옵션이 최대 힙 크기를 제어하며 동적 메모리이기 때문이다.

 

댓글