Java Management Extensions 라는 프로그램이다.
JMX는 JVM에서 구동하는 어플리케이션의 상태, JVM의 시스템 상태를 모니터링하기 위한 도구를 제공하는 Java API(표준 API)이다. (이 안에 기본 구현체도 들어가 있음)
JMX를 이용해서 JVM내부의 상태를 모니터링 할 수 있고, 다른 메트릭 시스템(프로메테우스, 마이크로메타)과 연동해서 통일된 인터페이스로 monitoring을 할 수 있다.
API제공하다보니 확장성이 장점이다.
이미지 출처 : https://download.manageengine.com/MEngine_Web.pdf
JMX는 자바 애플리케이션의 메모리, 스레드, 힙, 클래스 로딩 등 내부 리소스를 모니터링하고 제어하기 위한 프레임워크다.
크게 다음의 3계층으로 구성되어 있다:
Instrumentation Level은 실제 어플리케이션 내부의 데이터를 수집하고 외부에 노출하는 역할을 한다.
이 계층에서 사용하는 컴포넌트가 바로 MBean(Managed Bean) 이다.
자바에서 instrumentation은 코드에 조작을 가해 동작을 삽입하거나 모니터링 정보를 추가하는 것을 말한다.
일반적인 프로그래밍 용어는 아니며, 주로 자바에서 사용되는 개념이다.
예를 들어 바이트코드를 수정하여 클래스가 동작 중에 추가적인 정보를 수집하도록 만드는 방식 등이 이에 해당한다.
MBean은 Managed Bean의 줄임말로, JMX(Java Management Extensions) 환경에서 관리 가능한 자바 객체를 의미한다.
MBean은 애플리케이션의 리소스(메모리, 스레드, 설정값 등)를 외부에서 모니터링하거나 제어할 수 있도록 하는 인터페이스를 제공한다.
MBean은 특정한 디자인 패턴에 따라 작성되어야 하며, javax.management.MBean 인터페이스를 따르는 객체이다.
JMX 시스템은 이러한 MBean을 등록하고 관리하면서, 모니터링 도구나 관리자가 애플리케이션 상태를 실시간으로 확인하거나 제어할 수 있게 해준다.
즉, MBean은 JMX 시스템에서 데이터를 노출하거나 제어 명령을 전달하기 위한 핵심 인터페이스 역할을 한다.
MBean은 애플리케이션 내부 리소스를 관리 가능한 형태로 표현한 자바 객체이다.
즉, 다음과 같은 기능을 수행한다:
유형 | 설명 | 특징 |
---|---|---|
Standard MBean | 변경이 많지 않은 시스템 구성을 위한 정형화된 MBean. MBean 인터페이스를 직접 구현함 | 구조가 단순하고 명확함 |
Dynamic MBean | 런타임 시 동적으로 속성 및 메서드를 구성할 수 있는 MBean. 인터페이스 없이 구현 가능 | 유연성이 높고 동적 환경에 적합 |
Model MBean | 어떤 리소스에도 재사용 가능하며 동적으로 설치 가능한 범용 MBean. RequiredModelMBean 구현 필요 | 재사용 가능성과 유연성을 동시에 확보 |
Open MBean | JMX 스펙에 따라 기본 타입(String, int, CompositeData 등)만 사용하는 제한적 MBean | 이기종 시스템 간 데이터 호환성이 좋음 |
참고: 실무에서는 대부분 Standard MBean이 기본이며, Model MBean은 범용 프레임워크나 라이브러리에서 사용된다.
Open MBean은 주로 외부 시스템과의 통신이 중요할 때, Dynamic MBean은 런타임 구성이 잦은 고급 환경에서 주로 사용된다.
Agent Level은 Instrumentation Level에서 정의한 MBean을 등록하고 관리하는 계층이다.
MBeanServer를 통해 모든 MBean을 중앙에서 관리하며, 외부 클라이언트(예: 모니터링 도구)의 요청을 처리하는 역할을 한다.
Agent는 클라이언트가 접근할 수 있는 인터페이스이기도 하며, 클라이언트는 이 레벨을 통해 어플리케이션 내부 상태에 접근한다.
Connector 혹은 Adaptor는 외부에서 들어오는 요청을 받아들이는 계층이다.
이 계층은 다양한 네트워크 프로토콜(TCP, HTTP, SNMP 등)에 맞게 데이터를 전달하거나 변환하는 역할을 한다.
예를 들어, 클라이언트가 HTTP로 요청할 경우 HTTP에 맞는 응답 포맷을 제공해야 하며, SNMP 요청의 경우도 마찬가지다.
이러한 역할을 어댑터가 수행하며, 프로토콜에 맞는 처리 방식이 정의되어 있어야 한다.
실무적인 포인트
- 대부분의 대규모 시스템이나 오픈소스 모니터링 도구는 이미 커넥터, 어댑터, MBean을 잘 구현해놓았기 때문에, 사용자 입장에서는 이들을 활용하는 쪽에 집중하면 된다.
- MBean이나 커넥터를 직접 개발하는 경우가 아니라면 이 구조를 깊이 있게 구현까지 이해할 필요는 없으며, 필요한 정보만 스크랩하여 사용하는 것이 일반적이다.
다음 도구들을 이용해서 같은 host machine에서 pid로 모니터링을 할 수 있다. (설치 4.5)
JMX는 기본적으로 같은 JVM 내부에서만 동작하지만, Java 옵션을 활용하면 외부 호스트에서 리모트로 접근할 수 있도록 설정할 수 있다.
이를 통해 외부의 모니터링 시스템이나 관리자가 애플리케이션의 MBean 정보를 조회하거나 조작할 수 있다.
애플리케이션 실행 시 아래와 같은 Java 옵션을 지정해야 한다
Remote에서 조회하기 위해서는 다음 Java Parameter 로 설정할 수 있다.
-Dcom.sun.management.jmxremote=true \
-Dcom.sun.management.jmxremote.port=[jmx remote port] \
-Dcom.sun.management.jmxremote.ssl=false \
-Dcom.sun.management.jmxremote.authenticate=false \
|설정 항목| 설명|
|-Dcom.sun.management.jmxremote=true
|JMX 리모트 기능을 활성화|
|-Dcom.sun.management.jmxremote.port
|리모트 접속에 사용할 포트 번호 지정|
|-Dcom.sun.management.jmxremote.ssl=false
|SSL 암호화 비활성화 (실습용)|
|-Dcom.sun.management.jmxremote.authenticate=false
|인증 비활성화 (실습용)|
※ ssl
및 authenticate
옵션은 보안이 중요한 환경에서는 반드시 true로 설정해야 한다. 여기서는 실습 목적으로 false 설정을 사용하였다.
JmxExample.java
import java.util.Random;
public class JmxExample implements Runnable {
public void run() {
try {
Thread.sleep(1000); //1s
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
System.out.println(Thread.currentThread().getName());
}
public static void main(String[] args) throws InterruptedException {
JmxExample runnable = new JmxExample();
while (true) {
int random = new Random(System.currentTimeMillis()).nextInt();
ThreadGroup tg1 = new ThreadGroup("ThreadGroup" + random);
Thread t1 = new Thread(tg1, runnable, random + "-thread1");
t1.start();
Thread t2 = new Thread(tg1, runnable, random + "thread-2");
t2.start();
Thread t3 = new Thread(tg1, runnable, random + "thread-3");
t3.start();
System.out.println("Thread Group Name: " + tg1.getName());
tg1.list();
Thread.sleep(3 * 1000);
}
}
}
스레드 그룹을 하나 만들고 그 스레드 그룹에 3개의 스레드를 소켓시켜서 하나 실행시키고 하나의 스레드는 슬립을 하고 아무 것도 안 하는 것이다. 그리고 와일문을 돌리면서 매번 새로운 스레드 그룹과 새로운 스레드들을 만들면서 로그를 남기게 하는 프로그램이다.
그래서 반복적으로 여러 가지 스레드를 쓰는 프로그램이라고 보면 된다.
VM Options
-Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=8081 -Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.manage
VisualVm 으로 확인한다.
https://github.com/prometheus/jmx_exporter 에서 다운로드 및 가이드를 확인한다.
Java application에 agent를 붙여서 port로 노출하는 방법, java process와는 별도의 process에서 http로 노출하는 방법 두 가지가 있다.
내가 실행하는 자바 프로세스에서 프로메테우스가 자기 포트로 직접 자기 내부에서 JMX를 읽어서 노출하는 방법, 내가 실행하는 자바 프로세스랑은 별도로 어차피 JMX 포트에 익스포지 해놨으니까 그걸 이 친구가 읽어서 별도의 프로세스에서 Http서버로 익스포지 한다. 이 방법이 있다.
실습에서는 별도의 http server로 띄운다.
아까 위에 github에서 .jar를 다운받은 다음에 프로젝트 위치로 이동시켜두고
java -jar <다운받은파일> <프로메테우스로 노출하고 싶은 포트> <config.yaml>
이렇게 실행.
java -jar jmx_prometheus_httpserver-0.17.2.jar $your_prometheus_port config.yaml
포트는 아까 로컬호스트로 설정했으니 8082로 실습할 예정.
config.yaml 예제
hostPort: localhost:$your_jmx_port
rules:
- pattern: ".*"
hostport에는 내가 실행하고자 하는 JMX가 있는 호스트랑 포트를 넣으면 되고
rules 의 패턴 ".*"은 수집한 거 다 내놔 라는 얘기다. (여기서 필터링 가능)
나는 JMX 익스포지는 했는데 프로메테우스를 깜빡하고 같이 안 붙였다. 이런 경우엔
Standalone 방식으로 하면 스크랩 할 수 있다. 그리고 외부에서도 스크랩 할 수 있다.
아무 메세지가 없으면 잘 붙은 것이다
http://localhost:$your_prometheus_port/metrics
에서 확인한다.
다운로드, 또는 JDK 경로에 jvisualvm 으로 설치되어 있는 경우도 있다.
VisualVM은 GUI로 JVM의 상태를 확인할 수 있다. Remote host 도 JMX 포트로 연결해서 확인할 수 있는 점이 장점이다.
현재 상태 확인, 덤프 남기기 둘 다 가능하다.
다음 과정에서 배울 thread dump, heap dump 도 VisualVM으로 남길 수 있다.
JDK의 기본 JVM 분석 도구이다. 쉽게 사용할 수 있고, JMX로 리모트 연결도 가능하다. 현재 상태를 그래프로 확인할 수 있고, thread의
stack trace를 실시간으로 확인할 수 있다는 것이 장점이다.