고급 모니터링

프로그래밍으로 제니퍼 에이전트를 확장하는 방법과 제니퍼 서버가 수집한 성능 데이터를 다른 애플리케이션과 연동하는 방법을 설명한다. 그리고 SOA(Service Oriented Architecture) 구현을 위한 솔루션을 모니터링하는 방법을 설명한다.

제니퍼 에이전트 확장

제니퍼는 자바 애플리케이션 소스 코드의 수정없이 제니퍼 에이전트를 통해서 다양한 성능 데이터를 수집한다. 그런데 제니퍼 에이전트가 제공하는 API와 어뎁터로 모니터링 기능을 확장할 수 있다.

이를 위해서 간단한 프로그래밍이 필요하고 소스 코드를 컴파일하려면 JENNIFER_HOME/agent 디렉토리의 jennifer.jar 파일을 클래스 패스에 등록해야 한다.

ActiveTraceUtil

ActiveTraceUtil 클래스를 이용해 트랜잭션 데이터를 임의로 수정할 수 있다. ExtraAgentUtil 클래스와 함께 제니퍼 에이전트 확장 방법 중에서 애플리케이션 소스 코드의 수정을필요로 한다. 따라서 제니퍼 에이전트를 제거하기 위해서는 ActiveTraceUtil 클래스를 사용하는 모든 소스 코드를 수정해야 한다. ActiveTraceUtil 클래스의 API는 다음과 같다.

package com.javaservice.jennifer.agent;

public class ActiveTraceUtil {

   public ActiveTraceUtil();
   public ActiveTraceUtil(ActiveObject activeObject);

   public String getGUID();
   public void setGUID(String guid);

   public long getTUID();

   public void setAppException(String message);
   public void setAppException(int exceptionCode, String message);

   public void setApplicationName(String name);
   public void addActiveServiceName(String name);

   public void setExternalTransactionName(String name);

   public static void addProfile(String message);
}

ActiveTraceUtil 객체는 트랜잭션을 처리하는 특정 자바 쓰레드에 배타적인 방식으로 사용되어야 한다. 즉, 전역 변수나 javax.servlet.Servlet 객체의 멤버 필드로 사용해서는 안된다. 메소드 안에서 로컬 변수로 이 객체를 생성해서 사용하는 것을 권장한다.

애플리케이션 이름 수정

제니퍼 에이전트의 옵션을 통해서 설정하는 방법(애플리케이션 서비스 네이밍을 참조) 이외에 ActiveTraceUtil 클래스의 setApplicationName 메소드로 애플리케이션 이름을 설정할 수 있다.

ActiveTraceUtil activeTraceUtil = new ActiveTraceUtil();
activeTraceUtil.setApplicationName("APP_NAME_001");

트랜잭션에서 앞의 코드가 수행되면 해당 트랜잭션의 애플리케이션 이름은 APP_NAME_001이 된다.

그리고 애플리케이션 이름은 변경하지 않고, [실시간 모니터링 | 애플리케이션] 메뉴의 액티브 서비스 탭에 나타나는 애플리케이션 이름에 임의의 내용을 추가하려면 ActiveTraceUtil 클래스의 addActiveServiceName 메소드를 사용한다.

ActiveTraceUtil activeTraceUtil = new ActiveTraceUtil();
activeTraceUtil.addActiveServiceName("ACTIVE_NAME_001");

애플리케이션 이름이 /index.jsp인 트랜잭션에서 앞의 코드가 수행되면 액티브 서비스 탭에는 다음과 같이 나타난다.

/index.jsp?ACTIVE_NAME_001

액티브 서비스 탭

ActiveTraceUtil 클래스의 addActiveServiceName 메소드를 한번 이상 호출할 수 있다.

activeTraceUtil.addActiveServiceName("ACTIVE_NAME_001");
...
activeTraceUtil.addActiveServiceName("ACTIVE_NAME_002");

애플리케이션 이름이 /index.jsp인 트랜잭션에서 앞의 코드가 수행되면 액티브 서비스 탭에는 다음과 같이 나타난다.

/index.jsp?ACTIVE_NAME_001+ACTIVE_NAME_002

외부 트랜잭션 이름 수정

제니퍼 에이전트의 옵션을 통해서 설정하는 방법(외부 트랜젝션 네이밍을 참조) 이외에 ActiveTraceUtil 클래스의 setExternalTransactionName 메소드로 외부 트랜잭션 이름을 설정할 수 있다.

ActiveTraceUtil activeTraceUtil = new ActiveTraceUtil();
activeTraceUtil.setExternalTransactionName("TX_NAME_001");

트랜잭션에서 앞의 코드가 수행되면 외부 트랜잭션 이름은 TX_NAME_001이 된다.

임의의 예외를 발생시키기

ActiveTraceUtil 클래스의 setAppException 메소드를 통해서 트랜잭션 수행 중에 임의의 예외가 발생한 것으로 설정할 수 있다.

ActiveTraceUtil activeTraceUtil = new ActiveTraceUtil();
activeTraceUtil.setAppException("EXCEPTION_MESSAGE_001");

트랜잭션에서 앞의 코드가 수행되면 해당 트랜잭션에서 WARNING_CUSTOM_EXCEPTION 유형의 예외가 발생한 것으로 간주된다. setAppException 메소드의 파라미터는 예외 메시지가 된다.

예외 탭

예외에 대한 자세한 사항은 경보와 예외의 이해를 참조한다.

프로파일에 메세지 추가

ActiveTraceUtil 클래스의 addProfile 메소드로 X-View 프로파일 데이터에 임의의 메시지를 추가할 수 있다. 이 메소드는 다른 메소드와는 다르게 ActiveTraceUtil 클래스의 정적 메소드이다.

ActiveTraceUtil.addProfile("PROFILE_MESSAGE_001");

트랜잭션 수행 중에 앞의 코드가 수행되면 X-View 프로파일 데이터에 PROFILE_MESSAGE_001 메시지가 나타난다.

X-View 프로파일

이 메소드로 JSP 구간별 응답 시간 등을 손쉽게 확인할 수 있다.

<%
   ...
   ActiveTraceUtil.addProfile("JSP_POINT_001");
   new OneAction().execute();
   new TwoAction().execute();
   ActiveTraceUtil.addProfile("JSP_POINT_002");
   ...
%>

앞의 JSP가 수행되면 X-View 프로파일 데이터에서 JSP 구간별 분석을 할 수 있다.

JSP 구간별 프로파일

X-View 프로파일에 대한 자세한 사항은 X-View와 프로파일링을 참조한다.

트랜잭션 아이디 제어

ActiveTraceUtil 클래스의 getTUID 메소드로 트랜잭션의 UUID를 획득할 수 있다. 트랜잭션의 UUID는 제니퍼 에이전트가 자동으로 설정한다.

ActiveTraceUtil activeTraceUtil = new ActiveTraceUtil();
long uuid = activeTraceUtil.getTUID();

이를 통해서 제니퍼가 수집하는 트랜잭션 데이터와 비지니스 이벤트 혹은 데이터와의 연관 관계를 설정할 수 있다.

ActiveTraceUtil 클래스의 getGUID와 setGUID 메소드로 글로벌 트랜잭션 연계 추적을 위한 GUID를 설정할 수 있다.

ActiveTraceUtil activeTraceUtil = new ActiveTraceUtil();
activeTraceUtil.setGUID("UNIQUE_GUID_001");
...
String guid = activeTraceUtil.getGUID();

UUID는 long 유형이고, GUID는 java.lang.String 유형이다. 글로벌 트랜잭션 연계 추적과 관련한 자세한 사항은 글로벌 트랜잭션 연계추적을 참조한다.

ExtraAgent 어뎁터

제니퍼 에이전트가 기본적으로 수집하지 않는 데이터를 모니터링해야 하는 경우 ExtraAgent 어뎁터로 수집할 수 있다.

ExtraAgent 어뎁터를 사용하려면 우선 com.javaservice.jennifer.agent.ExtraAgent 인터페이스를 구현한 클래스를 작성해야 한다. ExtraAgent 인터페이스는 다음과 같다.

package com.javaservice.jennifer.agent;
import com.javaservice.jennifer.protocol.RmPacket;
public interface ExtraAgent {
   public RmPacket process(String agent);
}

ExtraAgent 어뎁터의 process 메소드에서 임의의 데이터를 수집한다. 수집한 데이터로 RmPacket 객체를 만들어서 이를 반환하면 제니퍼 에이전트가 제니퍼 서버 혹은 REMON에 이를 REMON 데이터 형태로 전송한다. 따라서 제니퍼 서버는 ExtraAgent 어뎁터에서 전송받은 데이터를 REMON이 전송한 REMON 데이터와 동일하게 취급한다.

다음은 자바 쓰레드의 상태별 개수를 수집하는 예제이다. JMX(Java Management Extension)를 이용하기 때문에 자바 1.5 이상에서 사용할 수 있다.

package example;

import java.lang.management.ManagementFactory;
import java.lang.management.ThreadMXBean;

import com.javaservice.jennifer.agent.ExtraAgent;
import com.javaservice.jennifer.protocol.RmPacket;
import com.javaservice.jennifer.type.INT;

public class ThreadCountExtraAgent implements ExtraAgent {

   public RmPacket process(String agent) {
      ThreadMXBean threads = ManagementFactory.getThreadMXBean();
      RmPacket result = new RmPacket("THREAD_COUNT", "EA1");
      result.addField("TOTAL", new INT(threads.getThreadCount()));
      result.addField("DAEMON", new INT(threads.getDaemonThreadCount()));
      return result;
   }
}

THREAD_COUNT는 REMON 데이터의 스크립트 아이디이고, EA1는 REMON 데이터의 에이전트 아이디이다. 스크립트 아이디와 에이전트 아이디에 대한 자세한 사항은 REMON 스크립트를 참조하고, RmPacket 클래스를 사용하는 자세한 방법은 RmPacket 클래스의 사용을 참조한다.

소스 코드를 컴파일한 후에 임의의 JAR 파일로 패키지한다.

다음은 ExtraAgent 어뎁터 사용에 필요한 설정이다. 제니퍼 에이전트의 extra_enable 옵션을 true로 설정한다.

extra_enable = true

제니퍼 에이전트의 extra_agent_class 옵션으로 ExtraAgent 인터페이스를 구현한 클래스를 설정한다. 2개 이상의 ExtraAgent 어뎁터를 사용하는 경우에는 세미 콜론[;]을 구분자로 구분한다.

extra_agent_class = example.ThreadCountExtraAgent

ExtraAgent 인터페이스를 구현한 클래스를 담고 있는 JAR 파일을 제니퍼 에이전트의 extra_agent_classpath 옵션으로 설정한다. 2개 이상의 JAR 파일을 사용하는 경우에는 세미 콜론[;]을 구분자로 구분한다.

extra_agent_classpath = /jennifer/extension.jar

ExtraAgent 어뎁터의 수행 주기를 제니퍼 에이전트의 extra_data_interval 옵션으로 설정한다. 단위는 밀리 세컨드이다.

extra_data_interval = 5000

ExtraAgent 어뎁터가 수집하는 데이터를 제니퍼 서버가 아닌 REMON에 전송하기 위해서는 추가적으로 제니퍼 에이전트의 extra_data_send_target 옵션으로 REMON의 IP 주소와 포트 번호를 설정해야 한다.

extra_data_send_target=127.0.0.1:7701

제니퍼 서버로 전송하는 경우와 REMON으로 전송하는 하는 경우의 프로토콜이 다르기 때문에 제니퍼 서버로 전송하는 경우에는 이 옵션을 설정해서는 안된다.

REMON으로 전송하면 필터를 이용해서 데이터를 다양한 방법으로 가공할 수 있다. 자세한 사항은 데이터 제어를 참조한다.

이 옵션들은 자바 애플리케이션을 정지하지 않고 수정할 수 있다. 단, ExtraAgent 구현 클래스를 수정한 경우에는 다음과 같은 방법으로 이를 반영한다.

단, 제니퍼 에이전트의 extra_agent_hotswap 옵션이 true로 설정되어 있어야 한다. 기본값은 true이다.

extra_agent_hotswap = true

제니퍼 서버는 ExtraAgent 어뎁터가 전송한 데이터를 REMON 데이터와 동일하게 처리한다. 따라서 ExtraAgent 어뎁터로 수집한 데이터를 모니터링하는 방법은 사용자 정의 차트를 참조한다. 다음은 자바 쓰레드 개수를 나타내는 라인 차트이다.

자바 쓰레드 개수 모니터링

CustomTrace 어뎁터

CustomTrace 어뎁터로 트랜잭션에서 호출되는 메소드의 전후로 임의의 작업을 수행할 수 있다.

CustomTrace 어뎁터를 사용하려면 우선 com.javaservice.lwst.CustomTraceAdapter 인터페이스를 구현한 클래스를 작성해야 한다. CustomTraceAdapter 인터페이스는 다음과 같다.

package com.javaservice.lwst;

public interface CustomTraceAdapter {

   public CustomStat start(String className, String methodName, Object traceParam);
   public void end(CustomStat stat, Throwable e);

}

트랜잭션에서 특정 클래스의 특정 메소드가 호출되면, 해당 메소드가 수행되기 전에 CustomTrace 어뎁터의 start 메소드가 호출된다. start 메소드의 첫번째 파라미터는 호출되는 클래스 이름이고, 두번째 파라미터는 호출되는 메소드 이름이다. 그리고 세번째 파라미터는 int와 long 등의 기본 유형이 아닌 객체 유형의 첫번째 메소드 파라미터이다.

그리고 해당 메소드의 수행이 완료되면 CustomTrace 어뎁터의 end 메소드가 호출된다. 그런데 start 메소드에서 null을 반환한 경우에는 end 메소드가 호출되지 않는다. end 메소드의 첫번째 파라미터는 start 메소드에서 반환한 CustomStat 객체이고, 두번째 파라미터는 해당 메소드에서 발생한 예외 객체이다. 예외가 발생하지 않았으면 null이 된다.

start 메소드에서 반환하는 com.javaservice.lwst.CustomStat 클래스는 다음과 같다. start 메소드에서 null을 반환하면 end 메소드가 호출되지 않기 때문에 임의의 처리가 필요하지 않는 클래스의 메소드 호출에 대해서는 null을 반환하는 것을 권장한다.

package com.javaservice.lwst;

   public class CustomStat {

   public String className;

   public String methodName;

   public long startTime;

   public Object traceValue;
}

다음은 CustomTrace 어뎁터로 예외를 처리하는 예제이다. 일반적으로 트랜잭션에서 발생한 예외가 트랜잭션이 종료하기 전에 처리되면 해당 트랜잭션은 성공한 것으로 간주된다.

public void execute() {
   try {
      new OrderManager().order("0-322-59443-1", 3);
   catch (IllegalStateException ignore) {
   }
}

OrderManager 클래스의 order 메소드는 재고가 부족하면 java.lang.IllegalStateException 예외를 던진다. 그런데 트랜잭션에서 앞의 코드가 수행되어도 catch 문에서 이 예외를 처리했기 때문에 트랜잭션은 성공한 것으로 간주된다. 그런데 CustomTrace 어뎁터를 이용하면 기존 소스 코드의 수정없이 이 트랜잭션을 실패한 것으로 처리할 수 있다.

ExceptionTraceAdapter 클래스는 CustomTraceAdapter 인터페이스를 구현한 클래스이다. end 메소드로 IllegalStateException 예외가 전달되면 ActiveTraceUtil 클래스의 setAppException 메소드로 트랜잭션에서 예외가 발생한 것으로 처리한다.

package example;

import com.javaservice.jennifer.agent.ActiveTraceUtil;
import com.javaservice.lwst.CustomStat;
import com.javaservice.lwst.CustomTraceAdapter;

public class ExceptionTraceAdapter implements CustomTraceAdapter {

   public CustomStat start(String className, String methodName, Object traceValue) {
      CustomStat result = new CustomStat();
      result.className = className;
      result.methodName = methodName;
      result.traceValue = traceValue;
      result.startTime = System.currentTimeMillis();
      return result;
   }

   public void end(CustomStat stat, Throwable e) {
      if (e != null && e instanceof IllegalStateException) {
         new ActiveTraceUtil().setAppException(e.getMessage());
      }
   }
}

다음은 [실시간 모니터링 | 애플리케이션] 메뉴의 예외 탭에서 이를 확인한 그림이다.

CustomTrace 어뎁터를 이용한 예외 처리

다음은 CustomTrace 어뎁터 사용에 필요한 설정이다. 우선 제니퍼 에이전트의 custom_trace_adapter_class_name 옵션으로 CustomTraceAdapter 인터페이스를 구현한 클래스를 설정한다. 하나의 CustomTrace 어뎁터만을 사용할 수 있다.

custom_trace_adapter_class_name = example.ExceptionTraceAdapter

CustomTraceAdapter 인터페이스를 구현한 클래스를 담고 있는 JAR 파일을 제니퍼 에이전트의 custom_trace_adapter_class_path 옵션으로 설정한다.

custom_trace_adapter_class_path = /jennifer/extension.jar

CustomTraceAdapter 구현 클래스를 수정한 경우에는 다음과 같은 방법으로 이를 반영한다.

단, 제니퍼 에이전트의 custom_trace_hotswap 옵션이 true로 설정되어 있어야 한다. 기본값은 true이다.

custom_trace_hotswap = true

모든 메소드의 호출에 CustomTrace 어뎁터가 적용되는 것은 아니다. 제니퍼 에이전트의 custom_trace로 시작하는 옵션을 통해서 CustomTrace 어뎁터가 적용될 메소드를 설정한다.

CustomTraceAdapter 인터페이스를 구현한 클래스에도 CustomTrace 어뎁터를 적용할 수 있다. 이 경우에 무한 반복 호출이 일어날 수 있다. 따라서 CustomTraceAdapter 인터페이스를 구현한 클래스에는 CustomTrace 어뎁터를 적용해서는 안된다.

예를 들어, 앞의 business.OrderManager 클래스에 CustomTrace 어뎁터를 적용하려면 제니퍼 에이전트의 custom_trace_class 옵션으로 설정한다.

custom_trace_class = business.OrderManager

그리고 business.ProductManager 클래스에도 CustomTrace 어뎁터를 적용하려면 [;]을 구분자로 custom_trace_class 옵션에 설정한다. custom_trace_class 옵션뿐만 아니라 CustomTrace 어뎁터 적용과 관련한 모든 옵션에 2개 이상을 설정하려면 [;]을 구분자로 사용한다.

custom_trace_class = business.OrderManager;business.ProductManager

CustomTrace 어뎁터는 특정 메소드에 적용된다. 즉, 앞의 예와 같이 설정하면 business.OrderManager 클래스의 모든 메소드에 CustomTrace 어뎁터가 적용된다. 따라서 특정 메소드만에만 CustomTrace 어뎁터를 적용하려면 제니퍼 에이전트의 custom_trace_target_method 옵션으로 설정한다.

custom_trace_target_method = order

그런데 CustomTrace 어뎁터를 적용할 클래스들 중에서 이름이 동일한 메소드가 있고, 이중 특정 클래스의 특정 메소드에만 CustomTrace 어뎁터를 적용하려면 다음과 같이 구체적으로 설정한다.

custom_trace_target_method = business.OrderManager.order

반대로 특정 메소드에만 CustomTrace 어뎁터를 적용하지 않으려면 제니퍼 에이전트의 custom_trace_ignore_method 옵션으로 설정한다.

custom_trace_ignore_method = business.OrderManager.checkStock

메소드의 접근자를 통해서도 CustomTrace 어뎁터를 적용할 수 있다. 예를 들어, public 접근자와 접근자가 없는 메소드에만 CustomTrace 어뎁터를 적용하려면 다음과 같이 설정한다.

custom_trace_access_method = public;none

custom_trace_access_method 옵션에 설정이 가능한 값은 다음과 같다.

그리고 특정 클래스를 상속한 모든 클래스에 CustomTrace 어뎁터를 적용하려면 제니퍼 에이전트의 custom_trace_super 옵션을 사용한다. 예를 들어, business.ejb.BaseSessionBean을 상속한 모든 클래스에 CustomTrace 어뎁터를 적용하려면 다음과 같이 설정한다.

custom_trace_super = business.ejb.BaseSessionBean

그러나 이 경우에 직접적으로 상속받은 클래스에만 CustomTrace 어뎁터를 적용한다. 예를 들어, A 클래스가 business.ejb.BaseSessionBean 클래스를 상속하고 B 클래스가 A 클래스를 상속했다면, A 클래스에는 CustomTrace 어뎁터를 적용하지만 B 클래스에는 CustomTrace 어뎁터를 적용하지 않는다.

특정 인터페이스를 구현한 모든 클래스에 CustomTrace 어뎁터를 적용하려면 제니퍼 에이전트의 custom_trace_interface 옵션을 사용한다. 예를 들어, business.IManager 인터페이스를 구현한 모든 클래스에 CustomTrace 어뎁터를 적용하려면 다음과 같이 설정한다.

custom_trace_interface = business.IManager

그러나 이 경우에 직접적으로 구현한 클래스에만 CustomTrace 어뎁터를 적용된다. 예를 들어, A 클래스가 business.IManager 인터페이스를 구현하고 B 클래스가 A 클래스를 상속했다면, A 클래스에는 CustomTrace 어뎁터를 적용하지만 B 클래스에는 CustomTrace 어뎁터를 적용하지 않는다.

클래스의 이름을 이용해서도 CustomTrace 어뎁터를 적용할 수 있다. 이 경우에는 제니퍼 에이전트의 custom_trace_prefix, custom_trace_postfix, custom_trace_ignore_prefix 옵션을 사용한다. 예를 들어, 이름이 business로 시작하는 모든 클래스에 CustomTrace 어뎁터를 적용하려면 다음과 같이 한다.

custom_trace_prefix = business

이름이 Manager로 끝나는 모든 클래스에 CustomTrace 어뎁터를 적용하려면 다음과 같이 한다.

custom_trace_postfix = Manager

특정 이름으로 시작하는 클래스에는 CustomTrace 어뎁터를 적용하지 않으려면 제니퍼 에이전트의 custom_trace_ignore_prefix 옵션을 사용한다. 이 옵션은 다른 모든 옵션에 우선한다.

custom_trace_ignore_prefix =

제니퍼 에이전트의 custom_trace로 시작하는 옵션을 통해서 동일한 내용을 다양한 방법으로 설정할 수 있다. CustomTrace 어뎁터를 적용하는데 있어서 custom_trace_target_method 옵션을 통해서 실제로 필요한 메소드에만 CustomTrace 어뎁터를 적용하도록 한다.

예를 들어, pkg.ClassA와 pkg.ClassB 클래스가 있다. 여기서 ClassA 클래스의 run 메소드와 ClassB 클래스의 process 메소드에 CustomTrace 어뎁터를 적용한다고 가정한다. 그런데 ClassB 클래스에 run 메소드가 존재하고 이 메소드에는 CustomTrace 어뎁터를 적용하지 않는다면 다음과 같이 설정한다.

custom_trace_class = pkg.ClassA;pkg.ClassB
custom_trace_target_method = run;process
custom_trace_ignore_method = pkg.ClassB.run

또는 다음과 같이 설정할 수도 있다.

custom_trace_class = pkg.ClassA;pkg.ClassB
custom_trace_target_method = pkg.ClassA.run;pkg.ClassB.process

제니퍼 에이전트에서 서버로 경보 전송

ExtraAgentUtil 클래스로 임의의 경보를 발령할 수 있다. ActiveTraceUtil 클래스와 함께 제니퍼 에이전트 확장 방법 중에서 애플리케이션 소스 코드의 수정을 필요로 한다. 따라서 제니퍼 에이전트를 제거하면 ExtraAgentUtil 클래스를 사용하는 모든 소스 코드를 수정해야 한다. ExtraAgentUtil 클래스의 전체 이름은 다음과 같다.

com.javaservice.jennifer.agent.ExtraAgentUtil

경보 발령을 위해서 ExtraAgentUtil 클래스가 제공하는 메소드는 다음과 같다.

경보에 대한 자세한 사항은 경보와 예외 유형을 참조한다.

성능 데이터 연동

제니퍼 서버가 수집한 성능 데이터를 다른 애플리케이션과 공유하는 방법을 설명한다. 이는 풀(Pull) 방법과 푸시(Push) 방법으로 나누어진다.

성능 데이터 연동 개념도

풀 방식의 성능 데이터 연동

외부 애플리케이션이 제니퍼 서버로 HTTP 요청을 하고, 이 요청을 받은 제니퍼 서버가 XML 형식의 문서를 반환하는 것이 풀 방식의 성능 데이터 연동이다.

일반 성능 데이터 조회

다음 요청을 통해서 요청 시점의 일반 성능 데이터를 XML 파일로 확인할 수 있다.

http://jennifer_server_ip:7900/get_perf_agent.jsp

XML 파일의 기본 골격은 다음과 같다.

<?xml version="1.0" encoding="UTF-8" ?>
   <perf version="4.0.1.1" jennifer="SYS1" time="2008-11-10 14:16:45.716">
</perf>

최상위 태그는 perf 태그이고, perf 태그의 속성은 다음과 같다.

그리고 perf 태그는 제니퍼 에이전트를 의미하는 instance 하위 태그로 구성된다.

<instance agent="TOT"
   ac0="1" ac1="1" ac2="0" ac3="5"
   act_serv="7"
   act_user="7"
   tps="25.633333"
   res_time="0.16205852"
   con_user="271.74252"
   error_rate="0.2"
   reject_rate="0.0"
   hit_hour="61679" visit_hour="4208"
   proc_cpu="0.0" proc_mem="0.0"
   hit_day="600767" visit_day="28807"
   alert_fatal="7" alert_error="3844" alert_warn="9874" />

<instance agent="W11" ...

다음은 각 속성에 대한 설명이다.

instance 태그 속성

필드명

설명

ac0 ~ ac3

경과 시간 구간별 액티브 서비스 개수를 의미한다.

act_serv

전체 액티브 서비스 개수로 각 구간별 액티브 서비스 개수의 합을 의미한다.

act_user

액티브 사용자 수

tps

서비스 처리율

res_time

평균 응답 시간

con_user

동시단말 사용자 수

error_rate

예외 발생률

reject_rate

PLC에 의한 서비스 거부율

hit_hour

현재 시간대 호출 건수

visit_hour

현재 시간대 방문자 수

proc_cpu

시스템 CPU 사용률

proc_mem

시스템 메모리 사용량

hit_day

금일 호출 건수

visit_day

금일 방문자 수

alert_fatal

금일 심각 경보 건수

alert_error

금일 에러 경보 건수

alert_warn

금일 경고 경보 건수

비즈니스 그룹 성능 데이터 조회

다음 요청을 통해서 요청 시점의 비즈니스 그룹별 성능 데이터를 XML 파일로 확인할 수 있다.

http://jennifer_server_ip:7900/get_perf_biz.jsp

XML 파일의 기본 골격은 다음과 같다.

<?xml version="1.0" encoding="UTF-8" ?>
   <perf version="4.0.1.1" jennifer="SYS1" time="2008-11-10 14:16:45.716">
</perf>

최상위 태그는 perf 태그이고, perf 태그의 속성은 다음과 같다.

그리고 perf 태그는 비즈니스 그룹을 의미하는 biz 하위 태그로 구성된다.

<biz id="BIZ/A" div="DIV" name="G01"
     res_time="0.11274193548387097" tps="2.066666666666667"
     accu_error="0" accu_hit="62" />

<biz id="BIZ/B" div="DIV" name="G02"
     res_time="3.1610000000000005" tps="0.43333333333333335"
     accu_error="0" accu_hit="13" />

다음은 각 속성에 대한 설명이다.

biz 태그 속성

필드명

설명

id

고유한 아이디

div

비즈니스 그룹 구분명

name

비즈니스 그룹 이름

res_time

비즈니스 그룹의 평균 응답 시간

tps

비즈니스 그룹의 서비스 처리율

accu_error

비즈니스 그룹의 누적 예외 건수

accu_hit

비즈니스 그룹의 누적 호출 건수

비즈니스 그룹을 통해서 특정 애플리케이션 그룹에 대한 서비스 처리율, 평균 응답 시간등의 데이터를 수집할 수 있다. 예를 들어, 주문이나 결제와 같은 중요한 업무에 대한 성능 데이터를 별도로 수집할 수 있다.

[구성 관리 | 비즈니스 그룹] 메뉴에서 비즈니스 그룹을 설정한다. 비즈니스 그룹을 추가하는 방법은 다음과 같다.

비즈니스 그룹에 대한 수정 사항을 반영하려면 비즈니스 그룹 목록 하단에 있는 [적용] 버튼을 클릭한다.

비즈니스 그룹과 관련한 정보는 다음과 같다.

비즈니스 그룹 정보

항목

설명

아이디

고유한 아이디로, 임의의 값을 입력한다. 경우에 따라서는 [/]를 구분자로 해서 트리 형태의 아이디 체계를 사용할 수도 있다.

구분명

REMON 데이터의 접미사가 된다. 구분명이 동일한 비즈니스 그룹은 동일한 REMON 데이터가 된다.

이름

비즈니스 그룹의 이름으로, REMON 데이터의 필드 이름이 된다.

애플리케이션

해당 비즈니스 그룹에 속하는 애플리케이션 이름을 줄바꿈을 구분자로 입력한다. 와일드 카드[*]를 사용할 수 있다.

외부 트랜잭션

해당 비즈니스 그룹에 속하는 외부 트랜잭션 이름을 줄바꿈을 구분자로 입력한다. 와일드 카드[*]를 사용할 수 있다.

외부 트랜잭션은 REMON 데이터로 수집되지 않는다. 단, [통계 분석 | 보고서 | 일일 보고서] 메뉴에서 해당 비즈니스 그룹에 대한 외부 트랜잭션 처리 현황을 확인할 수 있다.

도메인

제니퍼 서버를 선택한다.

에이전트

특정 제니퍼 에이전트에 대해서만 비즈니스 그룹 데이터를 도출하려면 콤마[,]를 구분자로 제니퍼 에이전트 아이디를 입력한다.

상태

비즈니스 그룹의 사용 여부를 나타낸다.

비즈니스 그룹을 설정하면 기본적으로 3개의 REMON 데이터를 수집한다.

비즈니스 그룹 REMON 데이터 목록

다음은 REMON 데이터에 대한 설명이다. BIZ_TPS_[구분명] - 비즈니스 그룹에 대한 서비스 처리율을 의미한다.

BIZ_RES_[구분명] - 비즈니스 그룹에 대한 평균 응답 시간을 의미한다.

BIZ_ERR_[구분명] - 비즈니스 그룹에 대한 3초 동안 발생한 예외 건수를 의미한다.

구분명이 같은 비즈니스 그룹은 동일한 REMON 데이터가 되고, 비즈니스 그룹의 이름은 REMON 데이터의 필드가 된다.

푸시 방식의 성능 데이터 연동

XVLog나 SMS 어뎁터로 제니퍼 서버가 수집한 성능 데이터를 다른 애플리케이션으로 전송하는 것이 푸시 방식의 성능 데이터 연동이다.

XVLog를 통한 X-View 트랜잭션 데이터 처리

XVLog 어뎁터로 실시간으로 수집한 X-View 트랜잭션 데이터에 대해 임의의 작업을 수행할 수 있다.

XVLog 어뎁터를 컴파일하려면 JENNIFER_HOME/server/lib/jenniferserver.jar 파일을 클래스 패스에 등록해야 한다.

XVLog 어뎁터를 사용하려면 우선 com.javaservice.server.XVLog 인터페이스를 구현한 클래스를 작성해야 한다. XVLog 인터페이스는 다음과 같다.

package com.javaservice.jennifer.server;

import com.javaservice.jennifer.util.CircularObjectQueue;

public interface XVLog {

   public void execute(CircularObjectQueue queue);

}

반복적으로 XVLog 인터페이스를 구현한 클래스의 execute 메소드가 호출된다. execute 메소드의 파라미터는 CircularObjectQueue 객체인데, 이 객체에는 X-View 트랜잭션 데이터를 나타내는 TxPerfPacket 객체가 담겨 있다.

CircularObjectQueue 객체에 담겨 있는 TxPerfPacket 객체는 다음과 같은 구조를 갖는다. public 접근자인 멤버 필드로 필요한 데이터를 확인할 수 있다.

package com.javaservice.jennifer.protocol;

public class TxPerfPacket {

   public long store_time;
   public long end_time;
   public int elapsed;
   public int cpu_time;
   public int sql_time;
   public int fetch_time;
   public int etx_time;
   public int service_name_hash;
   public long tx_uuid;
   public int client_ip;
   public long wmonid;
   public byte err_type;
   public String agent;
   
   //using for global transaction trace
   public String guid;

   public int agent_profile_key;
   public String user_id;
   public byte turnaround;
}

일반적으로 사용되는 멤버 필드는 store_time 필드부터 agent 필드까지이고, 나머지는 특별한 상황을 위해 준비된 멤버 필드이다.

다음은 XVLog 어뎁터로 X-View 트랜잭션 데이터를 콘솔에 기록하는 예제이다.

package example;

import java.text.DateFormat;
import java.text.SimpleDateFormat;

import com.javaservice.jennifer.protocol.TxPerfPacket;
import com.javaservice.jennifer.server.XVLog;
import com.javaservice.jennifer.server.db.HashedString_DB;
import com.javaservice.jennifer.util.CircularObjectQueue;
import com.javaservice.jennifer.util.IpUtil;

public class ConsoleXVLog implements XVLog {

   private static DateFormat df = new SimpleDateFormat("yyyyMMddHHmmssS");
   public void execute(CircularObjectQueue queue) {
      while (queue.size() > 0) {
         TxPerfPacket packet = (TxPerfPacket) queue.dequeue();
         String time = df.format(new java.util.Date(packet.end_time));
         String appName = HashedString_DB.getAPPL(packet.service_name_hash);
         System.out.println("Time=" + time + ", UUID=" 
                       + packet.tx_uuid + ", Agent=" + packet.agent + ", App="
                       + appName + ", Client IP=" 
                       + IpUtil.intToAddress(packet.client_ip) + ",
                       Elapsed Time="
                       + packet.elapsed + ", SQL Time=" 
                       + packet.sql_time + ", TX Time=" 
                       + packet.etx_time);
      }
   }
}

다음은 XVLog 어뎁터 사용에 필요한 설정이다. 우선 제니퍼 서버의 enable_xvlog 옵션을 true로 설정한다.

enable_xvlog = true

그리고 제니퍼 서버의 xvlog_class 옵션으로 XVLog 인터페이스를 구현한 클래스를 설정한다.

xvlog_class = example.ConsoleXVLog

XVLog 어뎁터를 컴파일한 후에 JAR 파일로 패키지하여 JENNIFER_HOME/server/common/lib 디렉토리에 복사한 후 제니퍼 서버를 재시작한다.

경보 데이터 연동

SMS 어뎁터로 경보 데이터를 다른 애플리케이션에 전송할 수 있다.

SMS 어뎁터를 컴파일하려면 JENNIFER_HOME/server/common/lib/jenniferserver.jar 파일을 클래스 패스에 등록해야 한다.

SMS 어뎁터를 사용하려면 우선 com.javaservice.jennifer.server.Sendsms 인터페이스를 구현한 클래스를 작성해야 한다. Sendsms 인터페이스는 다음과 같다.

package com.javaservice.jennifer.server;

public interface Sendsms {

   public void sendsms(ErrorObject[] alerts);

}

경보가 발령되면 Sendsms 인터페이스를 구현한 클래스의 sendsms 메소드가 호출된다. sendsms 메소드의 파라미터는 ErrorObject 객체 배열인데, 이 객체는 발령된 경보 데이터를 나타낸다.

com.javaservice.jennifer.server.ErrorObject 클래스는 다음과 같다.

package com.javaservice.jennifer.server;

import com.javaservice.jennifer.server.db.HashedString_DB;

public class ErrorObject {
   public long time = 0;
   public String agentname = null;
   public int type = 0;
   public int group_type = 0;
   public int reqkey_hash = 0;
   public String getReqKey() {
   return reqkey_hash == 0 ? null : HashedString_DB.getAPPL(reqkey_hash);
   }
   public float value = -1f;
   public String ipaddr = null;
   public String msg = null;
   public long tx_uuid;
}

public 접근자인 멤버 필드로 발령된 경보 내용을 확인할 수 있다. 다음은 각 필드에 대한 설명이다.

다음은 SMS 어뎁터로 ERROR_SERVICE_QUEUING 유형의 경보만을 데이터베이스에 저장하는 예제이다.

package example;

import com.javaservice.jennifer.server.ErrorObject;
import com.javaservice.jennifer.server.Sendsms;
import com.javaservice.jennifer.util.Def;

public class SaveAlertSendsms implements Sendsms {

   public void sendsms(ErrorObject[] alerts) {
      for (int i = 0; i < alerts.length; i++) {
         ErrorObject alert= alerts[i];
         if (alert.type == Def.ERROR_SERVICE_QUEUING) {
              // 데이터베이스 저장
         }
      }
   }

}

경보 데이터 연동 작업을 하는데 도움이 되는 클래스와 메소드에 대해서 설명한다. 첫번째는 ErrStr 클래스로, int 유형의 경보 유형을 java.lang.String 유형의 경보 이름으로 전환하는데 사용한다.

com.javaservice.jennifer.util.ErrStr

두번째는 AlertMsgCtr 클래스로, 경보 차트에 나타나는 메시지를 획득하는데 사용한다.

com.javaservice.jennifer.util.AlertMsgCtr

세번째는 TrapSender 클래스로, SNMP TRAP 메시지를 전송하는데 사용한다.

com.javaservice.jennifer.server.snmp.TrapSender

다음은 SMS 어뎁터 사용에 필요한 설정이다. 제니퍼 에이전트의 sms_adapter_class_name 옵션으로 Sendsms 인터페이스를 구현한 클래스를 설정한다.

sms_adapter_class_name = example.SaveAlertSendsms

두 개 이상의 SMS 어뎁터를 등록할 수 있는데 두개 이상의 SMS 전송 클래스는 세미 콜론[;]을 구분자로 구분한다.

SMS 어뎁터를 컴파일한 후에 JAR 파일로 패키지하여 JENNIFER_HOME/server/common/lib 디렉토리에 복사한다. 그리고 제니퍼 서버를 재시작한다.

Specialized 모니터링

SOA 구현을 위한 솔루션을 모니터링하는 방법을 설명한다.

해당 솔루션이 사용되는 방법에 따라서 다음에서 설명하는 내용이 적합하지 않을 수 있다. 따라서 해당 솔루션을 모니터링하는데 이 내용을 참고 자료로 사용하는 것을 권장한다.

오라클 WLI 모니터링

WLI(WebLogic Integration)를 모니터링하려면 다음 설정이 필요하다.

우선 애플리케이션 서비스 시작점이 javax.servlet.http.HttpServlet 클래스가 아닌 경우가 많기 때문에 제니퍼 에이전트의 tx_server_class 옵션과 tx_server_target_method 옵션에 다음 내용을 설정한다.

tx_server_class = com.bea.wli.knex.runtime.core.dispatcher.Dispatcher;weblogic.jms.client.JMSSession
tx_server_target_method = remoteDispatch;onMessage

그리고 애플리케이션 이름을 간단하게 하기 위해서 제니퍼 에이전트의 tx_server_ntype 옵션을 SIMPLE로 설정한다.

tx_server_ntype = SIMPLE

그리고 WLI는 JDBC 연결을 위해서 아파치 BeeHive를 사용한다. JDBC 모니터링을 위해서 제니퍼 에이전트의 jdbc_connection_justget 옵션을 다음과 같이 설정한다.

jdbc_connection_justget = org.apache.beehive.controls.system.jdbc.JdbcControlImpl.getConnectionFromDataSource(String,Class)

앞의 설정은 애플리케이션 서비스 시작점과 JDBC 모니터링을 위한 것이다. 그런데 상세한 모니터링을 위해서는 CustomTrace 어뎁터를 사용해서 애플리케이션의 주요 정보를 추출해야 한다.

애플리케이션 소스 코드의 수정이 필요하다.

단, WLI를 위한 CustomTrace 어뎁터 구현 클래스를 제니퍼가 제공하므로 CustomTrace 어뎁터를 별도로 구현할 필요는 없다. 제니퍼 에이전트의

custom_trace_adapter_class_name 옵션과 custom_trace_adapter_class_path 옵션을 다음과 같이 설정한다.

custom_trace_adapter_class_name = jennifer.custom.AdapterWLI
custom_trace_adapter_class_path = /jennifer/agent/lwst40.custom.jar

lwst40.custom.jar 파일은 JENNIFER_HOME/agent 디렉토리에 존재한다.

CustomTrace 어뎁터가 적용되는 클래스는 제니퍼 에이전트의 custom_trace_class 옵션으로 설정한다.

custom_trace_class = jennifer.JenniferGate

JenniferGate 클래스는 별도의 JAR 파일로 제공되는 것이 아니다. WLI를 사용하는 애플리케이션에서 다음 코드를 작성하여 클래스 패스에 등록한다.

package jennifer;

public class JenniferGate {
   public static void TRAN_NAME(String s){}
   public static void TRAN_STEP(String s){}
   public static void TRAN_ID(String s){}
   public static void WARN(String s){}
   public static void PROFILE(String s){}
}

그리고 애플리케이션에서 JenniferGate 클래스의 메소드를 호출하여 주요 정보를 설정하면, 앞에서 설정한 CustomTrace 어뎁터가 적용되면서 해당 정보를 추출한다. 다음은 JenniferGate 클래스의 메소드에 대한 설명이다.

오라클 ALSB 모니터링

제니퍼는 ESB(Enterprise Service Bus)와 같은 SOA 솔루션을 모니터링하는 것에 초점을 맞추고 있지는 않다. 하지만 ESB 기반 애플리케이션도 WAS에서 동작하기 때문에 제니퍼로 일정 부분의 모니터링이 가능하다. 여기서는 ESB 솔루션의 하나인 오라클 ALSB(Oracle Service Bus 혹은 Aqualogic Service Bus)를 제니퍼로 모니터링하는 방법을 설명한다.

우선, 제니퍼 에이전트의 alsb_enabled 옵션을 true로 설정한다. 기본 값은 true이다.

alsb_enabled = true

ALSB는 하나의 요청을 2개 이상의 자바 쓰레드, 즉 2개 이상의 트랜잭션으로 처리한다. 따라서 글로벌 트랜잭션 연계 추적이 필요하다. 글로벌 트랜잭션 연계 추적을 하려면 제니퍼 에이전트의 trace_related_transaction 옵션을 true로 설정한다.

trace_related_transaction = true

글로벌 트랜잭션 연계 추적을 하는데 있어서 제니퍼 에이전트가 트랜잭션에 부여하는 UUID를 GUID로 사용하기 위해서 제니퍼 에이전트의 enable_guid_from_tuid 옵션을 true로 설정한다.

enable_guid_from_tuid = true

그리고 ALSB가 요청을 처리하다가 발생한 예외 데이터를 추적해야 하다. ALSB는 예외 데이터를 SOA 메시지에 포함하여 전달한다. 따라서 예외 데이터를 확인하기 위해서는 SOA 메시지를 저장해야 한다. SOA 메시지를 저장하려면 제니퍼 에이전트의 dump_soa_msg 옵션을 true로 설정한다.

dump_soa_msg = true

dump_soa_msg 옵션을 true로 설정하면 제니퍼 에이전트는 SOA 메시지를 제니퍼 에이전트의 로컬 데이터베이스에 저장한다. 제니퍼 에이전트의 로컬 데이터베이스를 사용하려면 제니퍼 에이전트의 다음 옵션을 설정한다.

agent_db_enabled = true
agent_db_rootpath = .
agent_db_keep_days = 7

agent_db_enabled 옵션으로 제니퍼 에이전트의 로컬 데이터베이스 사용 여부를 설정하고, agent_db_rootpath 옵션으로 제니퍼 에이전트의 로컬 데이터베이스 디렉토리 위치를 설정한다. 그리고 agent_db_keep_days 옵션으로 데이터 보관 주기를 설정한다. 기본 값은 7일이다.

SOA 메시지는 X-View 메시지 텝에서 오른쪽 마우스를 클릭하면 나타나는 컨텍스트 메뉴의 [상세 보기] 메뉴를 통해서 확인할 수 있다.

ASLB는 하나의 요청을 여러 개의 자바 쓰레드, 즉 여러 개의 트랜잭션으로 처리한다. 첫번째 트랜잭션의 애플리케이션 서비스 시작점은 javax.servlet.http.HttpServlet 클래스이지만 다른 연계 트랜잭션의 애플리케이션 서비스 시작점은 별도로 설정해야 한다. 이를위해서 제니퍼 에이전트의 tx_server_class, tx_server_target_method, tx_server_ntype 옵션을 다음과 같이 설정한다.

tx_server_class = com.bea.wli.sb.pipeline.MessageProcessor
tx_server_target_method = processResponse
tx_server_ntype = CLASS

그리고 ALSB는 외부 애플리케이션과의 연계를 주요 목적으로 한다. 따라서 외부 트랜잭션 시작점을 설정해야 한다. 기본적으로 오라클 턱시도나 시벨 등과 연동하는 경우에는 제니퍼 에이전트의 tx_client_class, tx_client_target_method, lwst_txclient_method_using_return 옵션을 다음과 같이 설정한다.

tx_client_class = com.bea.wli.sb.transports.tuxedo.TuxedoTransportProvider;com.bea.alsb.transports.siebel.SiebelTransportProvider
tx_client_target_method = sendMessageAsync;processMessage
lwst_txclient_method_using_return = weblogic.wtc.gwt.TDMImport.getRemoteName();com.bea.alsb.transports.siebel.impl.SiebelEndpointConfigurationImpl.getBusinessName()

다른 외부 애플리케이션과 연동을 하면 이를 외부 트랜잭션 시작점에 추가해야 한다.

사용자는 ALSB에 의한 워크 플로우 단계들을 X-View 프로파일로 확인할 수 있고, X-View 차트의 GUID 뷰를 통해서 글로벌 트랜잭션 연계를 모니터링할 수 있다.

ALSB를 모니터링하면 제니퍼가 수집하는 호출 건수와 실제 호출 건수의 차이가 클 수 있다. 하나의 요청을 여러 개의 자바 쓰레드로 처리하면 제니퍼는 각각을 별도의 트랜잭션으로 간주하여 호출 건수도 증가시킨다. 따라서 호출 건수를 분석할 때는 상대적 추세 관점에서만 사용하는 것을 권장한다.

제니퍼 모바일

스마트 폰에서 사용하기 위한 제니퍼 클라이언트이다. 이것을 제니퍼모바일이라 부른다.

기본파라미터

제니퍼모바일화면에서는 DAte, Domain, Agent를 기본 파라미터로 선택해야 한다.

기본 파라미터

Daily Charts

조회를 원하는 차트 선택 단 일자별 데이터를 조회된다.

Daily Charts

Alert

발생한 경보 내역을 조회할 수 있다. 아래의 조건을 입력하고 검색하면 시간의 역순으로 출력된다.

Active Service

현재의 액티브 서비스 수와 상세 내역을 조회할 수 있다. 단 TOT가 선택된 경우에는 Active Service만 조회되고 일반 에이전트가 선택된 경우에는 해당에이전트의 시스템 CPU사용율 까지 보여진다.

Active Service

기타

Action 등록 및 사용

제니퍼모바일에서는 폰에서 서버 관리를 위한 주요 쉘을 호출할 수 있다. 제니퍼를 설치한 경우 예제는 서버 실행과 종료 프로세스 리스트 로그뷰등이 포함되었다.

실제 시스템을 제어하는 백도어가 될 수 있다 따라서 보안문제를 검증한 다음에 사용해야 한다.

제니퍼 에이전트 모듈을 시스템에 설치하고 $JENNIFEr_AGENT/action디렉토리에 있는 쉘파일들의 실행권한과 경로를 맞추어 주어야 한다.

main.sh를 실행하면 제니퍼 모바일의 요청을 처리하는 RmAgent가 실행된다.

JAVA_HOME=/usr/java
JENNIFER_SERVER=192.168.0.101

$JAVA_HOME/bin/java -cp ../rmagent/RmAgent.jar RmAgent.MobileAction \
     -a X11,X12,X13 \
     -t 127.0.0.1:6902 \
     -l 127.0.0.1:7715 \
     -cmd:start "./start.sh" \
     -cmd:stop ./stop.sh \
     -cmd:log ./log.sh \
     -cmd:ps ./ps.sh \
     -cmd:dummy2 ./dummy2.sh

main.sh 내부의 정보는 사용자가 직접 시스템 환경에 맞게 수정해야 한다.

각 Action은 모바일 화면에도 등록되어야 하는데 제니퍼서버의 설정에서 아래와 같이 등록한다

mobileActions=start:Start;stop:Stop;log:Log View;ps:Process

하나의 액션은 ” ;”으로 구분하여 등록한다. main.sh에 등록된 cmd:<action>에서 <action>의 이름을 기술하고 그것이 화면에서 보여질 이름을 적어준다.