java性能监控工具MoSKito学习--一步一步开始工作1,2

Start working, step by step 一步一步开始工作
1,Get MoSKito.获取MoSKito
2,Integrate MoSKito into your application.在你的应用中加入MoSKito
3,Configure MoSKito. 配置MoSKito
4,Provide additional config if necessary.如果有必要的话提供额外的配置
----------------
>Getting MoSKito-Essential 获取MoSKito-Essential
Working with MoSKito via Maven 通过Maven来和MoSKito一起工作
Maven 用户能够获得MoSKito通过简单的定义在它pom.xml文件中的dependency依赖
pom.xml中关于MoSKito Demo Project在GitHub是一个非常好的引用关于通过Maven来一起工作。
Include repository仓库设置
我们有自己的仓库,包含了你自己Maven的设置或者是你的仓库的代理。
在Maven的设置中添加如下部分:
<repositories>
        <repository>
                <id>provided</id>
                <url>http://nexus.anotheria.net/nexus/content/groups/public</url>
                <releases>
                        <enabled>true</enabled>
                </releases>
                <snapshots>
                        <enabled>true</enabled>
                </snapshots>
        </repository>
</repositories> //通常情况下,已经设置了repositories所以只要添加中间部分即可。
此时你使用一个代理,简单的使用代理的地址如下:
http://nexus.anotheria.net/nexus/content/repositories/releases/
Define dependencies 定义依赖
接着是定义pom中的依赖,当前发布版本中的MoSKito的模块如下:
<dependency>
    <groupId>net.anotheria</groupId>
    <artifactId>moskito-core</artifactId>
    <version>2.7.2</version>
</dependency>
<dependency>
    <groupId>net.anotheria</groupId>
    <artifactId>moskito-web</artifactId>
    <version>2.7.2</version>
</dependency>
<dependency>
    <groupId>net.anotheria</groupId>
    <artifactId>moskito-webui</artifactId>
    <version>2.7.2</version>
</dependency>
获取MoSKito的源码
MoSKito-Essential项目的源码地址为: https://github.com/anotheria/moskito/
ivy:不再支持
NextSteps 接下来
你已经通过Maven或者源码获得了MoSKito。
这样你能够控制你应用的性能数据,但是不能看他们。要看这些数据,你需要MoSKito-inspect模块,MoSKito内置的web接口。
所以,我们推荐下面的步骤:
1)把MoSKtio-WebUI嵌入一个Maven发布的war包中(具体在MoSKito-Essential模块部分介绍)
2) 把MoSKtio-WebUI嵌入你的应用(具体在MoSKito-Essential模块部分介绍)


>MoSKito-Essential Integration Guide 整合MoSKito-Essential的指导
AOP 面向切面
为了整合MoSKito在你的应用中并且监视你的数据和代码通过AOP,下面两个简单的步骤:
Step 1: Annotate classes and methods 步骤1:注解类和方法
对于类,添加@Monitor 注解
@Monitor
public class YourClass {}
对于方法,添加同样的@Monitor注解
public class YourClass {
  @Monitor public void firstMonitoredMethod(){...}
  @Monitor public void secondMonitoredMethod(){...}
  public void notMonitoredMethod(){...}
}
如果想监视一个类中的部分方法,部分不监视:
 1,添加@Monitor注解在目标类上
 2,然后添加@DontMonitor注解在你不想监视的方法上。
如:
@Monitor
public class YourClass {
  public void thisMethodWillBeMonitored(){...}//会监视


  @DontMonitor public void thisMethodWillBeExcludedFromMonitoring(){...}//不会
}
对于Counters有相同的工作流程
如:
@Count
public class PaymentCounter {}
你也可以定制自己的监视器通过一个producerld,subsystem或者category在monitor注解上
如:
@Monitor(producerId="MyProducer", subsystem="mySub", category="myCategory")
public class YourClass {}
Step 2: Alter pom.xml 步骤2:修改pom.xml
对类注解了监视后,告诉编译器实际编织他们。在Maven中,这个完成通过添加如下两段代码在你的pim.xml中:
<dependencies>
    <dependency>
        <groupId>net.anotheria</groupId>
        <artifactId>moskito-core</artifactId>
        <version>...</version>
    </dependency>
    <dependency>
        <groupId>net.anotheria</groupId>
        <artifactId>moskito-aop</artifactId>
        <version>...</version>
 </dependency>
 <!-----其他依赖包 --->
</dependencies>
然后添加构建部分:
<build>
    <plugins>
        <plugin>
            <groupId>org.codehaus.mojo</groupId>
            <artifactId>aspectj-maven-plugin</artifactId>
            <version>1.4</version>
            <configuration>
                <aspectLibraries>
                    <aspectLibrary>
                        <groupId>net.anotheria</groupId>
                        <artifactId>moskito-aop</artifactId>
                    </aspectLibrary>
                </aspectLibraries>
                <source>1.6</source>
                <target>1.6</target>
            </configuration>
            <executions>
                <execution>
                    <goals>
                        <goal>compile</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>
    </plugins>
</build>
这就是了。
 对于快速参考,请看moskito-examples GitHub项目中的aop模块:https://github.com/anotheria/moskito-examples
 或者:读取参考关于MoSKito-AOP所有的特征从模块Working With Annotations 指导
CDI
CDI整合和AOP整合十分相似,但有些不同。不管怎样,CDI也是两步设置:
Step 1: Annotate classes and methods 步骤1:注解类和方法
对于类,添加@Monitor注解(和AOP一样)
@Monitor
public class YourClass {}
你也可以绑定给注解一个特别的值,之后映射不同的拦截器
例如,我们提供了DAO,SERVICE和WEB拦截器,可以自动注入到生产者给特别的类。
@Monitor("service")
public class YourClass {}


@Monitor("dao")
public class AnotherClass {}


@Monitor("whatever")
public class YetAnotherClass {}
对于方法,使用相同的@Monitor注解
public class YourClass {
  @Monitor public void firstMonitoredMethod(){...}
  @Monitor public void secondMonitoredMethod(){...}
  public void notMonitoredMethod(){...}
  }
Step 2: Add interceptors to beans.xml and to the project 步骤2:添加拦截器在beans.xml然后加入工程。
为了**MoSKito的拦截器(不管是你自己的,还是构建进去的)对于CDI,添加他到bean.xml:
bean.xml
<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
       http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">


    <interceptors>
    <class>net.anotheria.moskito.integration.cdi.CountInterceptor</class>
    <class>net.anotheria.moskito.integration.cdi.CallInterceptor</class>


    <!-- Customized interceptors for @Monitor with parameters -->
        <class>net.anotheria.moskito.integration.cdi.WebCallInterceptor<class>
        <class>net.anotheria.moskito.integration.cdi.ServiceCallInterceptor</class>
        <class>net.anotheria.moskito.integration.cdi.DaoCallInterceptor</class>


    <!-- You may add your interceptor too -->
    <class>com.company.project.moskitointegration.MobileCallInterceptor</class>
    </interceptors>
</beans>
要想获取额外的信息和案例,看MoSKito-JBoss工程在GitHub中的CDI整合案例:https://github.com/anotheria/moskito-jboss
WEB 网站:网站整合被划分为多个子部分。
Filters 拦截
MoSKito提供了一系列内值的拦截用于不同的统计.所有下面的拦截都是监视相同的状态类型,FilterStats.不相同的是状态名字自身的获取不同。例如,RequestURIFilter只会在通过URL和DomainFilter通过服务名调用时才会调用。
下面的拦截器版本是2.2.3:


Filter:net.anotheria.moskito.web.filters.AsyncSourceTldFilter
Purpose:Separates traffic by top level source domain. This Filter is more secure than SourceTldFilter because it:
a) performs the lookup asynchronously, without support from container, and
b) is invulnerable to DNS attacks, for the same reason as a).
拦截器名称:AsyncSourceTldFilter
拦截器目的:通过*源域分割流量。这个拦截器比SourceTldFilter更安全因为它:
a)异步查看性能,没有来自容器的支持,并且
b)它不会受到DNS的攻击,同样的理由是a
Filter:net.anotheria.moskito.web.filters.DomainFilter
Purpose:Separates traffic by called server name.
拦截器名称:DomainFilter
拦截器目的:通过服务名称调用来分流
Filter:net.anotheria.moskito.web.filters.MethodFilter
Purpose:Separates traffic by HTTP Method (GET, POST, PUT).
拦截器名称:MethodFilter
拦截器目的:通过HTTP方法来分流(GET,POST,PUT)
Filter:net.anotheria.moskito.web.filters.RefererFilter
Purpose:Separates traffic by referrer (if any).
拦截器名称:RefererFilter
拦截器目的:通过推荐来分流(任何推荐)
Filter:net.anotheria.moskito.web.filters.RequestURIFilter
Purpose:Separates traffic by URL, in other words, you get request count, time, etc., for each callable URL in your system.
拦截器名称:RequestURIFilter
拦截器目的:通过URL分流,换句话说,你得到的请求数,时间等,对每一个通过URL调用你的系统的请求
Filter:net.anotheria.moskito.web.filters.SourceIpSegmentFilter
Purpose:Separates traffic by the first byte of IP4 Address.
拦截器名称:SourceIpSegmentFilter
拦截器目的:通过IP4地址的第一字节来分流
Filter:net.anotheria.moskito.web.filters.SourceTldFilter
Purpose:Separates traffic by top level client domain. This filter relies on container's resolving, which is switched off by default on most containers.
拦截器名称:SourceTldFilter
拦截器目的:通过*客户端源域分割流量。这个拦截器依赖于容器的解析,默认在大多数情况下是关闭的
Filter:net.anotheria.moskito.web.filters.UserAgentFilter
Purpose:Separates traffic by User Agent. Unfortunately, this filter uses the whole user-agent header as stat name and not just browser. The latter would be great, we are looking for contributions
拦截器名称:UserAgentFilter
拦截器目的:通过用户代理来分流。不幸的是,这个拦截器使用的是整个用户代理的头部作为状态名字并且不只是浏览器。后者比较伟大,我们在贡献部分查看。
对于上面的拦截器整合通过web.xml来完成:
web.xml
<filter>
  <filter-name>RequestURIFilter</filter-name>
  <filter-class>net.anotheria.moskito.web.filters.RequestURIFilter</filter-class>
  <init-param>
    <param-name>limit</param-name>
    <param-value>1000</param-value>
  </init-param>
</filter>
<filter-mapping>
  <filter-name>RequestURIFilter</filter-name>
  <url-pattern>/*</url-pattern>
</filter-mapping>


limit参数是用于阻止内存过载的。
因为状态的数量在MoSKito中并不是很有名,它添加了新的入口在fly。然而,因为每一个URL,每次调用,将会被监视。它很容易受到攻击通过不存在的URLs的调用。
为了阻止中个攻击,一个有限的状态名字大小被应用,1000应该可以很好的适用大多数生产网站。
Custom filters 客户拦截器
所有上面的拦截器(几乎是全部)被构建使用相同的原则:
1)继承net.anotheria.moskito.web.MoskitoFilter,
2) 实现 protected abstract String extractCaseName(ServletRequest req, ServletResponse res ).
例如案例,DomainFilter:
package net.anotheria.moskito.web.filters;
import net.anotheria.moskito.web.MoskitoFilter;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
 * This filter counts requests by domain.
 * @author lrosenberg
 *
 */
public class DomainFilter extends MoskitoFilter {
    @Override
    protected String extractCaseName(ServletRequest req, ServletResponse res) {
        return req.getServerName();
    }
}
随意来创建你自己的。
Listeners 监听
MoSKito说到两个构建中的监听:net.anotheria.moskito.web.session.SessionByTldListener 和net.anotheria.moskito.web.session.SessionCountProducer.SessionCountProducer简单的统计了所有的session数。SessionByTldListener(也是一个生产者,对不起给您带来不便)完成相同功能,但是额外统计了客户的TLD。所以,你能够监视多少你的用户来自中国,来自法国,来自加拿大等等。
两者都被整合通过web.xml
<listener>
  <listener-class>
    net.anotheria.moskito.web.session.SessionCountProducer
  </listener-class>
</listener>
<listener>
  <listener-class>
    net.anotheria.moskito.web.session.SessionByTldListener
  </listener-class>
</listener>
都用于统计新session,当前session数,删除的session数,和最小/最大活跃数,在其内部和状态。
Servlets
一个简单的方法和一个servlet整合,通过简单继承MoskitoHttpServlet并实现doGet方法来代替get方法。
PROXIES
java.lang.Proxy-代理很容易创建一个监听代理围绕着你实现的监视者。MoSKito提供一个特别的ProxyUtils类,允许通过快速和简单的方法创建MonitoringProxies。
我们假设你创建了一个服务接口:
public interface SimpleService{
    void doSomethingMethod();
}
和一个实现:
public class SimpleServiceImpl implements SimpleService{
    public void doSomethingMethod(){
    }
}
所有你需要做的就是包裹你的实现到一个代理,并且你可以如下来完成:
SimpleService service = ProxyUtils.createServiceInstance(new SimpleServiceImpl(), "default", SimpleService.class);
这个方法是一个快捷方法隐藏了许多实现细节你看不到。三个参数是:
new SimpleServiceImpl() : 你监视的实例
"default" :子系统,所有生产者有一个子系统。一个分类和一个生产者名字/id.分类是根据服务的方法名字来猜测的,生产者id更加类名生成。子系统保留。
SimpleService.class :要监视的接口。你可以指定多个(可变参数)。只有方法被特别标记在接口中才会监视。如果你调用toString()上述例子中的。它将不会被监视,因为它不是接口的一部分
上面的调用创建了一个新的监视实例,我们强烈建议你去创建更多而不是一个实例在你的类中,允许你通过资源分流。然而创建一个新的监视实例对每一个调用是不可行的,而且会导致内存泄漏。
更多ProxyUtils的方法:
/**
 * Creates a new proxied instance for an existing implementation.
 * @param <T> interface type.
 * @param impl the implementation of the interface.
 * @param name name of the producer.
 * @param category category of the producer, i.e. service, dao, api, controller.
 * @param subsystem subsystem of the producer, i.e. messaging, payment, registration, shop.
 * @param handler handler for the calls.
 * @param statsFactory the factory for the stats.
 * @param interf interfaces.
 * @return
 */
public static <T> T createInstance(T impl, String name, String category, String subsystem, IOnDemandCallHandler handler, IOnDemandStatsFactory statsFactory, Class<T> interf, Class<?>... additionalInterfaces){




/**
 * Creates a monitored proxy instance for a service. Service in this context means, that the ServiceStatsCallHandler and ServiceStatsFactory are used.
 * @param <T> the server interface.
 * @param impl the implementation of T.
 * @param name name for this instance.
 * @param category category of this instance.
 * @param subsystem subsystem of this instance.
 * @param interf class of T, main interface of the service.
 * @param additionalInterfaces additional helper interfaces, that should be supported as well.
 * @return
 */
public static <T> T createServiceInstance(T impl, String name, String category, String subsystem, Class<T> interf, Class<?>... additionalInterfaces){




/**
 * Shortcut method to create service instance. Creates an instance with service interface name as instance name, custom category and subsystem, ServiceStatsCallHandler and ServiceStatsFactory.
 * @param <T>
 * @param impl
 * @param category
 * @param subsystem
 * @param interf
 * @param additionalInterfaces
 * @return
 */
public static <T> T createServiceInstance(T impl, String category, String subsystem, Class<T> interf, Class<?>... additionalInterfaces){


/**
 * Shortcut method to create service instance with least possible effort. Creates an instance with service interface name as instance name, category service, ServiceStatsCallHandler and ServiceStatsFactory.
 * @param <T> service interface.
 * @param impl implementation of T.
 * @param subsystem subsystem of the service.
 * @param interf Class of T.
 * @param additionalInterfaces Additional interfaces if applicable.
 * @return
 */
public static <T> T createServiceInstance(T impl, String subsystem, Class<T> interf, Class<?>... additionalInterfaces){




public static <T> T createDAOInstance(T impl, String subsystem, Class<T> interf, Class<?>... additionalInterfaces){


小贴士关于ProxyUtils
下面的模式可以用于根据名字创建生产者:
 CLASSNAME+"_"+instanceCounter(从1开始)实例数
 在上述举例中,生产者ID将会是SimpleService-1,而不是SimpleService.这种模式是预防重复机制的一部分不允许被重写。
 然而ProxyUtils他自己只是MoskitoInvokationProxy(net.anotheria.moskito.core.dynamic.MoskitoInvokationProxy)类的一个公共类。虽然你可能永远都不需要直接使用它,它被命名如下:
SimpleService unmonitoredInstance = new SimpleServiceImpl();
MoskitoInvokationProxy proxy = new MoskitoInvokationProxy(
        unmonitoredInstance,
        new ServiceStatsCallHandler(),
        new ServiceStatsFactory(),
        "SimpleService",
        "service",
        "test-sub-system",
        SimpleService.class
        );
SimpleService monitoredInstance = (SimpleService)proxy.createProxy();
简单参数解析:
unmonitoredInstance : 在我们实现的实例中我们不想监视的接口
new ServiceStatsCallHandler() :代理调用的处理者。它处理所有的监听和统计
new ServiceStatsFactory() :IOnDemandStatsFactory给状态用
"SimpleService" : ProducerId 生产者id
"service" : Category 分类
"test-sub-system" :subsystem 子系统
SimpleService.class :Monitored interfaces (in this case one).被监视的接口,在这儿只有一个。
对于快速参考,看GitHub工程moskito-examples中的dynamicproxy模块。

关于三者的对比,见图AOP_CDI_Proxy.png:

java性能监控工具MoSKito学习--一步一步开始工作1,2

CALL EXECUTION 调用执行
调用执行是另一种告诉系统何时开始监视的方法。
通过AOP或者是Proxy整合,一个java方法变为一个自然的监视周期的开始和结束。然而
在一些网站,也许只有部分方法是相关的,又或者多个临界段在同一个方法中,这就是CallExecution的用武之地。
首先,一个非常简单的案例,这儿我们试着监视方法的一部分,当然我们需要一个生产者:
producer = new OnDemandStatsProducer<ServiceStats>("complexprocess", "category", "subsystem", ServiceStatsFactory.DEFAULT_INSTANCE);
ProducerRegistryFactory.getProducerRegistryInstance().registerProducer(producer);
现在我们有一个重要方法,我们想监视一个临界段:
public void methodWhichIsPartiallyMonitored(){
    //doing something
    //... bla boo bla
    //here comes the monitored part
    try{
        CallExecution execution = producer.getStats("methodWhichIsPartiallyMonitored").createCallExecution();
        execution.startExecution();
        //now we are doing something extremely important... 做你想做的事情
        execution.finishExecution();
    }catch(OnDemandStatsProducerException e){
        //react somehow, preferably smarter than the following line:
        throw new AssertionError("This should never happen in the example environment");
    }
    //doing something else
    //boo bla boo
}
最主要的不同是我们手动设置了监视的边界,代替了java方法自动生成的边界。下面的代码是一个清晰的案例关于在一个方法内监视多个边界:
public void methodWithMultipleComplexSubprocesses(){
    //doing something
    //... bla boo bla
    //here comes the beginning of our complex process
    try{
        CallExecution execution = producer.getStats("phase1").createCallExecution();
        execution.startExecution();
        //now we are doing something extremely important...做你想做的事
        execution.finishExecution();
        //now we are doing phase 2. For whatever reasons we have to do it in a loop or something.
        for (int i=0; i<3; i++){
            execution = producer.getStats("phase2").createCallExecution();
            execution.startExecution();
            //now we are doing something extremely important... 做你想做的事
            execution.finishExecution();
        }
        //no we do something else, until we finally have to do the last phase twice...
        execution = producer.getStats("phase3").createCallExecution();
        execution.startExecution();
        //now we are doing something extremely important...
        execution.finishExecution();
        execution = producer.getStats("phase3").createCallExecution();
        execution.startExecution();
        //now we are doing something extremely important... 做你想做的事
        execution.finishExecution();
        //now we are all set
 }catch(OnDemandStatsProducerException e){
        //react somehow, preferably smarter than the following line:
        throw new AssertionError("This should never happen in the example environment");
    }
    //doing something else
    // boo bla boo
}
好了,到这就结束了关于整合的一部分,接下来我们看关于MoSKito-Essential Configuration Guide MoSKito的配置指导