[Java] JMX MBean을 이용한 모니터링(Client, Server)
앞서서 기술한 JMX 내용에서 추가할 내용이 있었는데,
JMX MBean을 사용하기 위해 클라이언트 측과 서버 측의 클래스와 인터페이스를 동일하게 맞춰야 한다고 얘기했지만, 실제로 디버깅을 하며 테스트를 진행해보니 클라이언트 측에는 "클래스"까지 동일하게 맞출 필요가 없었습니다.
예제는 리눅스 환경 기반으로 JMX Server와 Sample Program(1초마다 running 문구가 호출되는 예제 프로그램)을 기동하여 Sample Program이 작동 중인지, 작동 중이지 않는지 Status를 확인하는 기능을 테스트하는 것입니다.
JMX는 Clinet에서 필요한 기능 또는 데이터를 서버를 통해서 가져와야만 할 때 JMX를 이용합니다.
특정 서버의 cpu 사용률이나 메모리 공간, 하드디스크 잔여 공간 등등...
그렇기 때문에 Server측에서 클라이언트가 요청한 실질적인 기능을 처리하고, 처리된 결과를 클라이언트에 반환, 클라이언트는 받은 데이터를 View에 노출시키는 흐름으로 되어 있습니다.
코드를 보며 서술하겠습니다.
1. 클라이언트 측
- Main Class
private ProcessFuncMBean mbeanModel;
/**
* JMX 서버 연결
*/
public void connectJMXServer() {
try {
System.out.println("server init...");
JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://192.168.0.24:7777/server");
JMXConnector jmxc = JMXConnectorFactory.connect(url, null);
System.out.println("connection init...");
// Get an MBeanServerConnection
MBeanServerConnection mbsc = jmxc.getMBeanServerConnection();
// JMXServer에서 등록한 ObjectName 생성
ObjectName mbeanName = new ObjectName("com.power21.ruleeditor.jmx.process.ProcessFunc:type=ProcessFunc");
// beanProxy 등록
mbeanModel = JMX.newMBeanProxy(mbsc, mbeanName, ProcessFuncMBean.class, true);
} catch (RuntimeErrorException e) {
System.out.println("Error --->" + e);
e.printStackTrace();
} catch (Exception e) {
System.out.println(e);
e.printStackTrace();
}
}
클라이언트는 Window환경입니다.
주의하여 볼 것이 ObjectName인데, mbeanName을 초기화 하는 문자열이 있습니다.
이 문자열에는 서버와 동기화하고 서버에서 수행할 기능에 대한 클래스의 타입 정보 입니다.
Class :: ProcessFunc
Interface :: ProcessFuncMBean
전역 변수로 선언된 private ProcessFuncMBean mbeanModel을 newMBeanProxy를 호출해서 ProcessFuncMBean 인터페이스를 인자로 넘겨주며 초기화를 시킵니다.
이렇게 인터페이스가 MBeanProxy로 등록이 되었으니, 인터페이스에 지정된 함수를 호출하면 서버에 수행할 기능을 요청하는 것이 됩니다.
- ProcessFuncMBean 인터페이스
package com.power21.ruleeditor.jmx.process;
public interface ProcessFuncMBean {
public boolean getProcessStatus(String cmd);
}
서버 측의 프로세스의 상태가 동작하고 있는지, 아닌지를 확인하려고 하니 getProcessStatus라는 이름으로 함수를 지정했고, boolean 값을 리턴하도록 인터페이스를 생성했습니다.
인자인 cmd는 상태를 확인하려는 프로세스의 이름입니다.
- Main Class
/**
* 테이블에 텍스트 박스 기준 아이템 추가
*/
public void addTableItem() {
boolean status = false;
try {
status = mbeanModel.getProcessStatus(txtProcessName.getText());
} catch (Exception ex) {
ex.printStackTrace();
status = false;
}
System.out.println(status);
}
저는 이클립스의 RCP의 SWT의 Table을 사용했기 때문에 addTableItem()함수를 호출해서 결과에 따라 테이블 아이템을 추가하도록 함수를 생성했습니다.
전역으로 선언한 mbeanModel에서 getProcessStatus를 호출하면 서버에서 기능을 수행하고 결과를 반환합니다.
2. 서버 측
서버 측은 리눅스 기반으로 구현되었습니다.
- Main Class
package org.jmxserver.main;
import java.rmi.registry.LocateRegistry;
import javax.management.MBeanServer;
import javax.management.MBeanServerFactory;
import javax.management.ObjectName;
import javax.management.remote.JMXConnectorServer;
import javax.management.remote.JMXConnectorServerFactory;
import javax.management.remote.JMXServiceURL;
import com.power21.ruleeditor.jmx.process.ProcessFunc;
public class Server {
private MBeanServer mbs = null;
public Server() {
mbs = MBeanServerFactory.createMBeanServer("");
ProcessFunc model = new ProcessFunc();
ObjectName name = null;
JMXServiceURL serviceURL = null;
try {
System.setProperty("java.rmi.server.hostname","192.168.0.24");
LocateRegistry.createRegistry(7777); //port
serviceURL = new JMXServiceURL("service:jmx:rmi:///jndi/rmi://192.168.0.24:7777/server");
name = new ObjectName("com.power21.ruleeditor.jmx.process.ProcessFunc:type=ProcessFunc");
JMXConnectorServer connector = JMXConnectorServerFactory.newJMXConnectorServer(serviceURL, null, mbs);
mbs.registerMBean(model, name);
connector.start();
}
catch(Exception e) {
e.printStackTrace();
}
}
public static void main(String argv[]) {
new Server();
System.out.println("Server Starting...");
}
}
클라이언트의 요청을 받을 수 있도록 지정한 아이피와 포트번호로 서버를 가동시킵니다.
서버 측도 마찬가지로 클라이언트와 동일하게 ObjectName에 패키지 명과 클래스의 타입 정보를 동일하게 작성합니다.
*실제 사용할 클래스의 패키지 명과 클래스 명입니다. 동일하지 않으면 오류가 발생합니다.
- ProcessFuncMBean 인터페이스
package com.power21.ruleeditor.jmx.process;
public interface ProcessFuncMBean {
public boolean getProcessStatus(String cmd);
}
서버 측에도 클라이언트에서 사용한 인터페이스를 동일하게 작성합니다.
클라이언트 함수를 요청했는데 반환 값이나 인자값, 함수명이 다르면 동작하지 않겠죠?
- ProcessFunc 클래스
package com.power21.ruleeditor.jmx.process;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class ProcessFunc implements ProcessFuncMBean, Serializable {
@Override
public boolean getProcessStatus(String cmd) {
Process process = null;
Runtime runtime = Runtime.getRuntime();
BufferedReader input = null; // 성공 버퍼
String msg = null; // 메시지
List<String> cmdList = new ArrayList<String>();
// 운영체제 구분 (window, window 가 아니면 무조건 linux 로 판단)
if (System.getProperty("os.name").indexOf("Windows") > -1) {
cmdList.add("cmd");
cmdList.add("/c");
} else {
cmdList.add("/bin/sh");
cmdList.add("-c");
}
// 명령어 셋팅
// java -jar ("program.jar")
cmdList.add("ps -ef | grep java | grep -v grep | grep " + cmd);
String[] array = cmdList.toArray(new String[cmdList.size()]);
for (String s : array) {
System.out.println(s);
}
try {
// 명령어 실행
process = runtime.exec(array);
input = new BufferedReader(new InputStreamReader(process.getInputStream()));
while((msg = input.readLine()) != null) {
if(!msg.trim().equals("")) {
msg = msg.substring(1);
System.out.println(msg);
System.out.println("프로세스 기동");
// 프로세스가 동작 중이라면 true
return true;
}
}
input.close();
return false;
} catch (IOException e) {
e.printStackTrace();
return false;
}
}
}
인터페이스를 implement해서 getProcessStatus 함수의 구체적인 코드를 작성합니다.
이 함수는 클라이언트 측에서 넘어온 프로세스의 이름을 가지고, 해당 프로세스가 서버에서 동작하고 있는지 아닌지를 판별합니다.
클라이언트에서 해당 함수가 호출되면 자연스럽게 서버의 getProcessStatus 함수가 실행되고 결과를 클라이언트에게 되돌려주는 흐름이죠.
3. 실행 결과
1초마다 running을 출력하는 SampleProgram를 실행시켰습니다.
프로세스가 실행되지 않을 때는 false, 실행되고 있을 때는 true로 값을 리턴해줍니다.
'Java > JMX' 카테고리의 다른 글
[오류해결] javax.management.NotCompliantMBeanException: (0) | 2020.08.24 |
---|---|
[Java] JMX Connector의 Server, Client 활용 (0) | 2020.03.18 |
[JAVA] JMX 예제 코드 및 jmxremote properties 설정 (0) | 2020.03.18 |
[JAVA] JMX의 mBean이란? JMX는 무엇인지? (0) | 2020.03.18 |