제3장 JMX 애플리케이션 개발

내용 목차

3.1. JMX 애플리케이션 구조
3.2. MBean 서버 연결
3.2.1. JEUS 유틸리티 사용
3.2.2. JNDI 사용
3.2.3. JMX Remote API 사용
3.3. Security 설정
3.4. MBean Object Names

JEUS 모니터링 서비스를 사용하기 위한 JEUS JMX 클라이언트 애플리케이션의 개발 및 설치 방법에 대해서 설명한다.

3.1. JMX 애플리케이션 구조

애플리케이션의 구조는 필요에 따라 다양한 형태가 있다. JEUS JMX 클라이언트 애플리케이션은 일반적인 구조로 구성되어 있고, 구성된 구조를 따라 수행한다.

다음은 JMX 클라이언트 애플리케이션의 수행 구조 및 과정이다.

  1. 환경설정(옵션 사항)

    JMX 클라이언트 애플리케이션을 위해 환경을 설정한다. 환경설정을 MBeanServer에 연결하기 전에 할 수 있다. 처리하려는 MBean을 질의하고, 그 결과를 받아서 처리할 수 있다.

    기본적인 환경설정에 대한 자세한 내용은 “제2장 JMX Manager 환경설정”을 참고한다.

  2. MBean 서버 연결

    MBean 서버로 접속하기 위한 방법은 다음과 같다.

    • jeus.management.RemoteMBeanServerFactory는 JEUS 유틸리티를 사용한다.

    • JNDI에 등록되어 있는 reference를 사용한다.

    • JMX Remote javax.management.remote.JMXServiceURL을 사용하여 javax.management.remote.JMXConnector를 얻을 수 있다.

    각 방법에 대한 자세한 내용은 각 절의 설명을 참고한다.

  3. 질의

  4. 질의 결과 처리

그 외에 JEUS 모니터링 서비스를 위한 보안 설정 방법과 JEUS JMX에서 ObjectName을 생성하는 규칙에 대해서 설명한다. 또한 JEUS 모니터링은 SNMP를 사용할 수도 있다. 사용 방법에 대한 자세한 내용은 "JEUS SNMP 안내서"를 참고한다.

참고

본 장에서 설명하는 내용을 이해하기 위해서 JMX Remote API 1.0과 Java EE Management 스펙에 대한 기본 지식이 필요하다. JMX Remote API에 대한 자세한 정보는 Oracle에서 제공하는 J2EE JMX Remote API 1.0 스펙과 JMX Remote API를 참고한다.

3.2. MBean 서버 연결

본 절에서는 MBean 서버로 접속하기 위한 방법에 대해서 설명한다.

3.2.1. JEUS 유틸리티 사용

본 절에서는 JEUS 유틸리티 클래스인 jeus.management.RemoteMBeanServerFactory를 사용해서 JEUS를 모니터링하는 JMX 애플리케이션에 대해서 설명한다. "MBean 서버 연결" 부분이 다른 방법과 차이가 있다.

다음은 JEUS 유틸리티를 사용하는 클라이언트 예제이다.

package jmxclient;

import java.util.Set;
import java.util.Iterator;
import java.util.Hashtable;
import javax.management.ObjectName;
import javax.management.MBeanServerConnection;
import javax.naming.Context;

/**
 * JMX Client which uses JEUS utility (RemoteMBeanServerFactory) class.
 */
public class JMXClientUsingJeusUtility {

    public static void main(String args[]) throws Exception {
        if(args.length < 3) {
            System.out.println("Required arguments: hostname username password");
            return;
        }
        
        // Step 1. Setting Environments
        String hostname = args[0];
        String username = args[1];
        String password = args[2];

        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "jeus.jndi.JNSContextFactory");
        env.put(Context.PROVIDER_URL, hostname);
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS, password);

        // Step 2. Getting MBeanServer
        MBeanServerConnection mbeanServer 
            = jeus.management.RemoteMBeanServerFactory.getMBeanServer(env);

        // Step 3. Query
        ObjectName jeusScope = new ObjectName("JEUS:*");
        Set objectNames = mbeanServer.queryNames(jeusScope, null);

        // Step 4. Handling the Query Result
        for(Iterator i = objectNames.iterator(); i.hasNext();) {
            System.out.println("[MBean] " + i.next());
        }
    }
}

"MBean 서버 연결"에서 JEUS가 제공하는 JEUS 유틸리티 클래스인 jeus.management.RemoteMBeanServerFactory를 사용했다. 이 클래스를 사용하면 간단하게 MBeanServerConnection을 얻을 수 있다.

위 예제를 작성한 후 컴파일하여 실행하면 JEUS 서버에 접속한 후 "JEUS:*"에 해당하는 MBean들의 목록을 출력한다. 예제 프로그램은 인자를 3개 받는데, 첫 번째는 서버의 hostname, 두 번째는 JEUS 사용자 이름, 마지막은 비밀번호이다.

user1@host1:~$ java -classpath .:$JEUS_HOME/lib/client/jclient.jar jmxclient.JMXClientUsingJeusUtility 127.0.0.1 administrator jeus

[2013.05.28 14:56:44][2] [t-1] [NET-0002] Beginning to listen to NonBlockingChannelAcceptor: /127.0.0.1:9756.
[MBean] JEUS:j2eeType=JeusService,jeusType=ThreadPool,JMXManager=adminServer,
J2EEServer=adminServer,name=threadpool.System
[MBean] JEUS:j2eeType=JeusService,jeusType=JEUSMPConnector,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSDestinationResource,
JMXManager=adminServer,J2EEServer=adminServer,JMSResource=adminServer_jms,
name=ExamplesQueue
[MBean] JEUS:j2eeType=JeusService,jeusType=JeusLogService,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=ThreadPool_WEBC,JMXManager=adminServer,
WebEngine=adminServer_servlet,J2EEServer=adminServer,WebListener=http1,name=http1
[MBean] JEUS:j2eeType=JeusService,jeusType=SecurityDomain,JMXManager=adminServer,
J2EEDomain=domain1,SecurityService=SecurityService,name=SYSTEM_DOMAIN
[MBean] JEUS:j2eeType=JeusService,jeusType=DeploymentPlanManagementService,
JMXManager=adminServer,J2EEDomain=domain1,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSConnectionFactoryResource,
JMXManager=adminServer,J2EEServer=adminServer,JMSResource=adminServer_jms,
name=ConnectionFactory
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSEngine,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer_jms
[MBean] JEUS:j2eeType=JeusService,jeusType=ServerDeploymentService,
JMXManager=adminServer,J2EEServer=adminServer,name=adminServer
. . .

참고

예제 프로그램은 jclient.jar가 있어야 실행할 수 있다. 기본적으로 jclient.jar는 JEUS_HOME/lib/client 아래에 위치한다.

3.2.2. JNDI 사용

본 절에서는 JNDI를 사용해서 JEUS를 모니터링하는 JMX 애플리케이션에 대해서 설명한다. "MBean 서버 연결" 부분이 다른 방법과 차이가 있다.

다음은 JNDI를 사용하는 클라이언트 예제이다.

package jmxclient;

import java.util.Set;
import java.util.Iterator;
import java.util.Hashtable;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.naming.Context;
import javax.naming.InitialContext;

/**
 * JMX Client which uses JNDI lookup.
 */
public class JMXClientUsingJndi {

    public static void main(String args[]) throws Exception {
        if(args.length < 4) {
            System.out.println("Required arguments: " 
                + "hostname username password target-name");
            return;
        }
        
        // Step 1. Setting Environments
        String hostname = args[0];
        String username = args[1];
        String password = args[2];

        // targetName could be server name,
        // for example, "adminServer", "server1"
        String targetName = args[3];
        
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "jeus.jndi.JEUSContextFactory");
        env.put(Context.PROVIDER_URL, hostname);
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS, password);

        // Step 2. Getting MBeanServerConnection
        InitialContext ctx = new InitialContext(env);
        JMXConnector connector = (JMXConnector)ctx.lookup("mgmt/rmbs/" + targetName);
        MBeanServerConnection mbeanServer = connector.getMBeanServerConnection();

        // Step 3. Query
        ObjectName jeusScope = new ObjectName("JEUS:*");
        Set objectNames = mbeanServer.queryNames(jeusScope, null);

        // Step 4. Handling the Query Result
        for(Iterator i = objectNames.iterator(); i.hasNext();) {
            System.out.println("[MBean] " + i.next());
        }
    }
}

JNDI에서 Lookup할 때에는 등록되어 있는 Connector(RMI Connector/JMXMP Connector)의 종류에 관계없이 같은 방식으로 사용이 가능하다. Lookup할 때 사용하는 Export Name은 여기서는 JEUS에서 사용하는 기본 naming 방식을 사용했다. 이 방식은 JNDI context mgmt/rmbs/<server-name> 형태의 이름을 사용한다.

위 예제를 작성한 후 컴파일하여 실행하면 JEUS 서버에 접속한 후 "JEUS:*"에 해당하는 MBean들의 목록을 출력한다. 예제 프로그램은 인자를 4개 받는데, 첫 번째는 서버의 hostname, 두 번째는 JEUS 사용자 이름, 세 번째는 비밀번호, 마지막은 서버 이름이다.

user1@host1:~$ java -classpath .:$JEUS_HOME/lib/client/jclient.jar jmxclient.JMXClientUsingJndi 127.0.0.1 jeus jeus adminServer

[2013.05.28 15:20:24][2] [t-1] [NET-0002] Beginning to listen to NonBlockingChannelAcceptor: /192.168.34.31:9756.
[MBean] JEUS:j2eeType=JeusService,jeusType=ThreadPool,JMXManager=adminServer,
J2EEServer=adminServer,name=threadpool.System
[MBean] JEUS:j2eeType=JeusService,jeusType=JEUSMPConnector,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSDestinationResource,
JMXManager=adminServer,J2EEServer=adminServer,JMSResource=adminServer_jms,
name=ExamplesQueue
[MBean] JEUS:j2eeType=JeusService,jeusType=JeusLogService,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=ThreadPool_WEBC,JMXManager=adminServer,
WebEngine=adminServer_servlet,J2EEServer=adminServer,WebListener=http1,name=http1
[MBean] JEUS:j2eeType=JeusService,jeusType=SecurityDomain,JMXManager=adminServer,
J2EEDomain=domain1,SecurityService=SecurityService,name=SYSTEM_DOMAIN
[MBean] JEUS:j2eeType=JeusService,jeusType=DeploymentPlanManagementService,
JMXManager=adminServer,J2EEDomain=domain1,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSConnectionFactoryResource,
JMXManager=adminServer,J2EEServer=adminServer,JMSResource=adminServer_jms,
name=ConnectionFactory
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSEngine,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer_jms
[MBean] JEUS:j2eeType=JeusService,jeusType=ServerDeploymentService,
JMXManager=adminServer,J2EEServer=adminServer,name=adminServer
. . .

그 외에 RMI Connector의 경우에는 JMXMP Connector가 별도로 띄워져 있는 경우에 기본 방식 이외의 이름을 reference export name으로 지정할 수 있다.

참고

1. 예제 프로그램은 jclient.jar가 있어야 실행할 수 있다. 기본적으로 jclient.jar는 JEUS_HOME/lib/client 아래에 위치한다.

2. RMI Connector 설정의 자세한 내용은 “2.3.2. RMI Connector”를 참고한다.

3. JNDI의 자세한 정보에 대해서는 JEUS Server 안내서”의 “제4장 JNDI Naming Server”를 참고한다. 만약에 JMX 애플리케이션이 서블릿 또는 EJB에서 실행된다면 JNDI 파라미터에 대한 설정은 필요하지 않다.

3.2.3. JMX Remote API 사용

본 절에서는 JMX Remote API를 사용해서 JEUS를 모니터링하는 JMX 애플리케이션에 대해서 설명한다. "MBean 서버 연결" 부분이 다른 방법과 차이가 있다.

다음은 JMX Remote API를 사용하는 클라이언트 예제이다.

package jmxclient;

import java.util.Set;
import java.util.Iterator;
import java.util.Hashtable;
import javax.management.MBeanServerConnection;
import javax.management.ObjectName;
import javax.management.remote.JMXServiceURL;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.naming.Context;

/**
 * JMX Client which uses JMX Service URL.
 * RMI Connector should be turned on in JEUS 
 * and the JNDI name of it is required here.
 */
public class JMXClientUsingJmxUrl {

    public static void main(String args[]) throws Exception {
        if(args.length < 4) {
            System.out.println("Required arguments: " 
                + "hostname username password connector-exportname");
            return;
        }
        
        // Step 1. Setting Environments
        String hostname = args[0];
        String username = args[1];
        String password = args[2];

        // the JMX RMIConnector export name
        String exportName = args[3];
        
        Hashtable env = new Hashtable();
        env.put(Context.INITIAL_CONTEXT_FACTORY, "jeus.jndi.JNSContextFactory");
        env.put(Context.PROVIDER_URL, hostname);
        env.put(Context.SECURITY_PRINCIPAL, username);
        env.put(Context.SECURITY_CREDENTIALS, password);

        // Step 2. Getting MBeanServer
        JMXServiceURL url = new JMXServiceURL("service:jmx:rmi:///jndi/" + 
         exportName);

        JMXConnector connector = null;
  try {
         connector = JMXConnectorFactory.newJMXConnector(url,env);
         // connect to JMXConnectorServer 
         connector.connect();
         MBeanServerConnection mbeanServer = connector.getMBeanServerConnection();

         // Step 3. Query
         ObjectName jeusScope = new ObjectName("JEUS:*");
         Set objectNames = mbeanServer.queryNames(jeusScope, null);

         // Step 4. Handling the Query Result
         for(Iterator i = objectNames.iterator(); i.hasNext();) {
             System.out.println("[MBean] " + i.next());
         }
  } finally {
   // Always close the JMXConnector
   connector.close();
  }
    }
}

참고

JMX Remote API를 사용하기 위해서는 JMX Manager에 있는 'RMI Connector' 항목을 설정해야 한다. RMI Connector 설정에 대한 자세한 내용은 “2.3.2. RMI Connector”를 참고한다.

위 예제를 작성한 후 컴파일하여 실행하면 JEUS 서버에 접속한 후 "JEUS:*"에 해당하는 MBean들의 목록을 출력한다. 예제 프로그램은 인자를 4개 받는데, 첫 번째는 서버의 hostname, 두 번째는 JEUS 사용자 이름, 세 번째는 비밀번호, 마지막은 RMI Connector ExportName이다.

다음 실행 결과에서는 'ExportName'을 'RMIConnector'로 설정한 경우이다.

user1@host1:~$ java -classpath .:$JEUS_HOME/lib/client/jclient.jar jmxclient.JMXClientUsingJmxUrl 127.0.0.1 jeus jeus RMIConnector

[2013.05.28 15:21:29][2] [t-1] [NET-0002] Beginning to listen to NonBlockingChannelAcceptor: /192.168.34.31:9756.
[MBean] JEUS:j2eeType=JeusService,jeusType=ThreadPool,JMXManager=adminServer,
J2EEServer=adminServer,name=threadpool.System
[MBean] JEUS:j2eeType=JeusService,jeusType=JEUSMPConnector,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSDestinationResource,
JMXManager=adminServer,J2EEServer=adminServer,JMSResource=adminServer_jms,
name=ExamplesQueue
[MBean] JEUS:j2eeType=JeusService,jeusType=JeusLogService,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=ThreadPool_WEBC,JMXManager=adminServer,
WebEngine=adminServer_servlet,J2EEServer=adminServer,WebListener=http1,name=http1
[MBean] JEUS:j2eeType=JeusService,jeusType=SecurityDomain,JMXManager=adminServer,
J2EEDomain=domain1,SecurityService=SecurityService,name=SYSTEM_DOMAIN
[MBean] JEUS:j2eeType=JeusService,jeusType=DeploymentPlanManagementService,
JMXManager=adminServer,J2EEDomain=domain1,name=adminServer
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSConnectionFactoryResource,
JMXManager=adminServer,J2EEServer=adminServer,JMSResource=adminServer_jms,
name=ConnectionFactory
[MBean] JEUS:j2eeType=JeusService,jeusType=JMSEngine,JMXManager=adminServer,
J2EEServer=adminServer,name=adminServer_jms
[MBean] JEUS:j2eeType=JeusService,jeusType=ServerDeploymentService,
JMXManager=adminServer,J2EEServer=adminServer,name=adminServer
. . .

참고

예제 프로그램은 jclient.jar가 있어야 실행할 수 있다. 기본적으로 jclient.jar는 JEUS_HOME/lib/client 아래에 위치한다.

3.3. Security 설정

JMX를 사용하여 JEUS 서버에 등록되어 있는 여러 MBean들이 제공하는 속성을 읽거나 작업할 경우 JEUS는 해당 연결을 맺은 사용자가 속성을 읽을 권한이 있는지 작업을 수행할 권한이 있는지를 검사한다. 각각 MBean을 사용할 때 필요한 권한에 대한 정보는 JEUS API 문서를 참고한다.

API 문서는 다음 위치에서 찾을 수 있다.

JEUS_HOME/docs/api

참고

API 문서는 MBean을 사용할 때 필요한 권한(Permission Name)뿐만 아니라 ObjectNamePattern, 속성(Attribute), 작업(Operation) 등에 대한 정보도 제공하고 있다.

JMX 애플리케이션에서 사용자 이름이나 비밀번호와 같은 정보는 서버에 접속해서 MBeanServerConnection을 생성할 때 제공한다. 일반적으로 MBeanServerConnection을 생성할 때는 다음과 같은 코드를 사용하는데, 코드를 살펴보면 Hashtable로 전달하는 환경설정 정보에 사용자 이름과 비밀번호가 들어가는 것을 확인할 수 있다.

. . .

    JMXServiceURL serviceURL = 
            new JMXServiceURL("service:jmx:jmxmp://127.0.0.1:9999/adminServer");

    Map<String, Object> env = new HashMap<String, Object>();
    env.put(Context.SECURITY_PRINCIPAL, id);
    env.put(Context.SECURITY_CREDENTIALS, password);
    env.put(Context.INITIAL_CONTEXT_FACTORY, "jeus.jndi.JEUSContextFactory");
    env.put("jmx.remote.x.request.timeout", "10");

    JMXConnector connector = JMXConnectorFactory.connect(serviceURL, env);
    MBeanServerConnection connection = connector.getMBeanServerConnection();

. . .

이때 사용하는 사용자 이름과 비밀번호, 권한 설정은 JEUS Security를 이용해서 설정한다. JEUS Security 설정 방법에 대한 자세한 내용은 JEUS Security 안내서”의 “2.5. 보안 시스템 사용자 정보 설정”JEUS Security 안내서”의 “2.6. 보안 시스템 정책 설정”을 참고한다.

3.4. MBean Object Names

ObjectName은 MBean 객체의 기본 JMX 객체 이름이다. ObjectName의 형식은 JMX 표준 형식이지만 JMX 구현이 각각 다르기 때문에 특정 벤더에 따라 값이 달라질 수 있다. JMX MBean들의 계층 구조는 벤더마다 다르고, MBean들도 벤더에 따라 여러 가지가 있다.

JEUS ObjectName의 문법은 다음과 같다.

<domain_name>: j2eeType=<j2eeType_value>, name=<name_value>,
    [<parent-j2eeType_value>], [jeusType = <jeusType_value>],
    [isTargetable = <isTargetable_value>],
    JMXManager = <JMXManager_value> [,*]

또는

<domain_name>: *

ObjectName은 <domain_name>으로 시작해야 하고, 각 이름과 값의 짝이 순차적으로 규정되지 않는다.

예를 들면 다음은 둘 다 JEUS 도메인 MBean의 objectname을 얻어온다.

JEUS:j2eeType=J2EEDomain,JMXManager=adminServer, *
JEUS:JMXManager=adminServer, j2eeType=J2EEDomain, *

다음은 각 항목에 대한 설명이다.

  • <domain_name>

    • ObjectName의 도메인 이름으로 값은 'JEUS'이다.

  • j2eeType

    • MBean은 J2EE 타입이며, J2EE Management 스펙에 의해 기술된다.

    • 다음 값들 중 하나를 설정한다.

      AppClientModuleEJBModuleEntityBean
      J2EEApplicationJ2EEDomainJ2EEServer
      JAXRResourceJCAConnectionFactoryJCAManagedConnectionFactory
      JCAResourceJDBCDataSourceJDBCDriver
      JDBCResourceJMSResourceJNDIResource
      JTAResourceJVMJavaMailResource
      JeusServiceMessageDrivenBeanResourceAdaptor
      ResourceAdapterModuleServletStatefulSessionBean
      StatelessSessionBeanURLResourceWebModule
  • name

    • MBean의 이름으로 각각의 MBean Object에는 유일한 값이 있다. 예를 들면 "adminServer"라는 서버가 실행하는 JVM의 이름은 'adminServer'이다.

  • parent-j2eeType

    • MBean의 상위 J2EE 타입으로 각 MBean들에 계층이 규정되어 있다. 예를 들면 "JDBCDriver"의 상위 J2EE 타입은 'JDBCDataSource'이다.

  • jeusType

    • JEUS JMX에서 정의된 MBean들의 타입이다. "JeusService" J2EE 타입만 몇 가지 jeusType을 가질 수 있다.

    • 다음 값들 중 하나를 설정한다.

      EJBEngineJMSClientResourceJMSConnectionFactoryResource
      JMSDestinationResourceJMSDurableSubscriberResourceJMSEngine
      JMSPersistenceStoreManagerJMSServiceChannelSecurityDomain
      SecurityPolicySecurityServiceSecuritySubject
      SessionContainerSessionContainerCentralSessionContainerP2P
      ThreadPoolThreadPool_WEBCWebEngine
      WebListenerWebServices 

  • isTargetable

    • 설정값은 blooean 타입으로 사용자 AP(EJB, 서블릿, JSP)가 deploy되어 isTargetable 동작하는 MBean에서는 반드시 true로 설정되어야 한다.

  • JMXManager

    • MBean 서비스를 제공하는 JMXManager의 이름이다. 일반적으로 JMXManager 항목의 값은 해당 JMXManager가 속한 서버 이름과 동일하다.