性能测试Jmeter压测ZooKeeper-自定义java请求

   要想通过自定义java请求来压测ZooKeeper,那么我们就需要做两件事情,第一我们需要知道java如何操作ZooKeeper,第二就是怎么能将我们写的jar包让jmeter识别,首先我们先来干第一件事。

一、java操作ZooKeeper

以下的代码是网上百度找到的,经过了一点点修改(对于测试其它的可以找其它的测试代码)

package com.comtop.ZookApi;

import java.util.concurrent.CountDownLatch;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;

/**
 * Zookeeper base学习笔记
 */
public class ZookeeperBase {

    /** zookeeper地址 */
    static final String CONNECT_ADDR = "10.10.3.136:32372";
    /** session超时时间 */
    static final int SESSION_OUTTIME = 2000;// ms
    /** 信号量,阻塞程序执行,用于等待zookeeper连接成功,发送成功信号 */
    static final CountDownLatch connectedSemaphore = new CountDownLatch(1);

    public static void main(String[] args) throws Exception {

        ZooKeeper zk = new ZooKeeper(CONNECT_ADDR, SESSION_OUTTIME,
                new Watcher() {
                    public void process(WatchedEvent event) {
                        // 获取事件的状态
                        KeeperState keeperState = event.getState();
                        EventType eventType = event.getType();
                        // 如果是建立连接
                        if (KeeperState.SyncConnected == keeperState) {
                            if (EventType.None == eventType) {
                                // 如果建立连接成功,则发送信号量,让后续阻塞程序向下执行
                                System.out.println("zk 建立连接");
                                connectedSemaphore.countDown();
                            }
                        }
                    }
                });

        // 进行阻塞
        connectedSemaphore.await();

        System.out.println("..");
//         创建父节点
//         zk.create("/testRoot", "testRoot".getBytes(), Ids.OPEN_ACL_UNSAFE,
//         CreateMode.PERSISTENT);

//         创建子节点
//         zk.create("/testRoot/children", "children data".getBytes(),
//         Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);

        // 获取节点洗信息
//         byte[] data = zk.getData("/testRoot/children", false, null);
//         System.out.println(new String(data));
//         System.out.println(zk.getChildren("/testRoot", false));
        // 修改节点的值
//         zk.setData("/testRoot/children", "modify data root".getBytes(), -1);
//         byte[] data = zk.getData("/testRoot/children", false, null);
//         System.out.println(new String(data));
// 如果存在节点则删除节点
         if (null != zk.exists("/testRoot/children", false)) {
             // 删除节点
             zk.delete("/testRoot/children", -1);
             System.out.println(zk.exists("/testRoot/children", false));
         }
        zk.close();

    }

}

二、自定义java请求

一、环境准备
        1、新建一个java工程
        2、导入jar包:ApacheJMeter_core.jar     ApacheJMeter_java.jar    (该包在本地C:apache-jmeter-3.0libext下,当然路径取决于本地环境)
                这两个jar是使用jmeter最基础的jar,能够让你的代码在jmeter中运行起来,如果在写代码的过程中需要其他的jar,自行导入。
 
二、写代码前该知道的
        1、如果想要让你的代码在jmeter中运行起来,在创建类的时候需要去继承AbstractJavaSamplerClient抽象类或者是实现JavaSamplerClient接口
            AbstractJavaSamplerClient抽象类是JavaSamplerClient接口的子类,当你不需要复写所有的需要复写的方法时,那么你只需要去继承AbstractJavaSamplerClient抽象类即可。
 
            如果你选择了实现JavaSamplerClient接口,那么你需要复写的方法有:
                         public SampleResult runTest(JavaSamplerContext context) {}
                         public void setupTest(JavaSamplerContext context) {}
                         public void teardownTest(JavaSamplerContext context) {}
                         public Arguments getDefaultParameters() {}
            这4个方法就必须要复写,但是如果选择继承AbstractJavaSamplerClient这个抽象类,那么只需要复写你需要的方法即可。
 
        2、方法说明:
                    public Arguments getDefaultParameters() {}
                            这个方法由Jmeter在进行添加javaRequest时第一个运行,它决定了你要在GUI中默认显示出哪些属性。
                    public void setupTest(JavaSamplerContext context) {}
                            这个方法相当于loadrunner中的init,我们可以用它来进行一些初始化的动作。
                    public SampleResult runTest(JavaSamplerContext context) {}
                            这个方法相当于loadrunner中的action,我们的核心测试代码就在这里了。
                    public void teardownTest(JavaSamplerContext context) {}
                            这个方法相当于loadrunner中的end,收尾的工作可以由它来做。
 
        3、除了以上2点,我们一般还需要去实现Serializable,序列化标记接口,这样可以让我们的类去实现序列化。
 
整体代码如下:
package com.comtop.ZkApiJM;
 
 
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
 
import org.apache.jmeter.config.Arguments;
import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient;
import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext;
import org.apache.jmeter.samplers.SampleResult;

import java.util.concurrent.CountDownLatch;

import javax.management.RuntimeErrorException;

import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher;
import org.apache.zookeeper.Watcher.Event.EventType;
import org.apache.zookeeper.Watcher.Event.KeeperState;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper.States;
import org.apache.zookeeper.ZooKeeper;

//public Arguments getDefaultParameters();设置可用参数及的默认值;
//public void setupTest(JavaSamplerContext arg0):每个线程测试前执行一次,做一些初始化工作;
//public SampleResult runTest(JavaSamplerContext arg0):开始测试,从arg0参数可以获得参数值;
//public void teardownTest(JavaSamplerContext arg0):测试结束时调用;

public class ZkjavaRequest extends AbstractJavaSamplerClient implements Serializable  {
 
    /** zookeeper地址 */
    private String conn_addr;    //存储用户输入的zk地址
//    测试用的数据
//    private static String conn_addr1;
//    private static String session_timeout1;
//    private static String zk_father1;
//    private static String zk_children1;
//    private static String zk_context1;
//    private static String resultData1;
    
    private static final String ConnAddrName="conn_addr" ;    //设置GUI页面显示的变量名称
    //设置GUI页面默认显示的变量值,默认值为空
    private static final String ConnAddrValueDefault="10.10.3.136:32372";
    
    /** session超时时间 */
    private String session_timeout;    //存储用户输入的session超时时间(单位ms)
    
    private static final String SessTimeName="session_timeout" ;    //设置GUI页面显示的变量名称
    //设置GUI页面默认显示的变量值,默认值为空
    private static final String SessTimeValueDefault="5000";

    //zk父节点
    private  String zk_father = "test";    //存储用户输入的zk父节点
    private static final String ZkFatherName="zk_father" ;    //设置GUI页面显示的变量名称
    //设置GUI页面默认显示的变量值,默认值为空
    private static final String ZkFatherValueDefault="/test";
    
    /** 信号量,阻塞程序执行,用于等待zookeeper连接成功,发送成功信号 */
    static final CountDownLatch connectedSemaphore = new CountDownLatch(1);
    
    //zk连接对象
    private ZooKeeper zk;
    
    // resultData变量用来存储响应的数据,目的是显示到查看结果树中。
    private String resultData;

    // 测试代码
//    public static void main(String[] args) {
//        haha();
//    }
//
//    public static void haha(){
//        conn_addr1 = "10.10.3.136:32372";
//        session_timeout1 = "2000";
//        zk_father1 = "/test1";
//        zk_children1 = "/test2";
//        zk_context1 = "test2";
//        try {
//            ZooKeeper zk = new ZooKeeper(conn_addr1, Integer.valueOf(session_timeout1),
//                    new Watcher() {
//                        public void process(WatchedEvent event) {
//                            // 获取事件的状态
//                            KeeperState keeperState = event.getState();
//                            EventType eventType = event.getType();
//                            // 如果是建立连接
//                            if (KeeperState.SyncConnected == keeperState) {
//                                if (EventType.None == eventType) {
//                                    // 如果建立连接成功,则发送信号量,让后续阻塞程序向下执行
//                                    System.out.println("zk 建立连接");
//                                    connectedSemaphore.countDown();
//                                }
//                            }
//                        }
//                    });
//            connectedSemaphore.await();
//            // 如果存在父节点则不创建父节点
//             if (null == zk.exists(zk_father1, false)) {
//                 //               创建父节点
//               zk.create(zk_father1, zk_father1.getBytes(), Ids.OPEN_ACL_UNSAFE,
//               CreateMode.PERSISTENT);
//             }
//          // 创建子节点
//              zk.create(zk_father1+zk_children1, zk_context1.getBytes(),
//              Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
//              // 获取节点洗信息
//            byte[] data = zk.getData(zk_father1+zk_children1, false, null);
//            resultData1 = new String(data);
//            System.out.println(new String(data));
//            System.out.println(zk.getChildren("/testRoot", false));
//        } catch (Exception e) {
//            throw new RuntimeException(e);
//        }
//
//}
  
    /*
     * 这个方法用来控制显示在GUI页面的属性,由用户来进行设置。
     * 此方法不用调用,是一个与生命周期相关的方法,类加载则运行。
     * (non-Javadoc)
     * @see org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient#getDefaultParameters()
     */
    
    @Override
    public Arguments getDefaultParameters() {
        System.out.println("读取属性值");
        Arguments params = new Arguments();
        params.addArgument("conn_addr",String.valueOf(ConnAddrValueDefault));
        params.addArgument("session_timeout", String.valueOf(SessTimeValueDefault));
        params.addArgument("zk_father", String.valueOf(ZkFatherValueDefault));
        params.addArgument("zk_children","");
        params.addArgument("zk_context","");
        return params;
    }
 
    /**
     * 初始化方法,初始化性能测试时的每个线程
     * 实际运行时每个线程仅执行一次,在测试方法运行前执行,类似于LoadRunner中的init方法
     */
 
    @Override
    public void setupTest(JavaSamplerContext jsc) {
        conn_addr = jsc.getParameter(ConnAddrName, ConnAddrValueDefault);
        session_timeout = jsc.getParameter(SessTimeName, SessTimeValueDefault);
        zk_father = jsc.getParameter(ZkFatherName, ZkFatherValueDefault);
        try {
            zk = new ZooKeeper(conn_addr, Integer.valueOf(session_timeout),
                    new Watcher() {
                        public void process(WatchedEvent event) {
                            // 获取事件的状态
                            KeeperState keeperState = event.getState();
                            EventType eventType = event.getType();
                            // 如果是建立连接
                            if (KeeperState.SyncConnected == keeperState) {
                                if (EventType.None == eventType) {
                                    // 如果建立连接成功,则发送信号量,让后续阻塞程序向下执行
                                    System.out.println("zk 建立连接");
                                    connectedSemaphore.countDown();
                                }
                            }
                        }
                    });
            if (States.CONNECTING == zk.getState()) { 
                connectedSemaphore.await();
            }
            // 如果存在父节点则不创建父节点
             if (null == zk.exists(zk_father, false)) {
                 //               创建父节点
               zk.create(zk_father, zk_father.getBytes(), Ids.OPEN_ACL_UNSAFE,
               CreateMode.PERSISTENT);
             }
        } catch (Exception e) {
            // TODO Auto-generated catch block
//            e.printStackTrace();
            throw new RuntimeException(e);
        }
        // 进行阻塞
//        System.out.println("..");
         
    }
 
    @Override
    public SampleResult runTest(JavaSamplerContext arg0) {
        String zk_children = arg0.getParameter("zk_children");    //获取zk_children
        String zk_context = arg0.getParameter("zk_context");    //获取zk_context
//        System.out.println(zk_context+" "+zk_children);
        /*
         * SampleResult这个类是用来将测试结果输出到查看结果树中的。  
         * 并且也是用来控制事务的开始和结束的。  
         */
    
        SampleResult results = new SampleResult();
        results.setSampleLabel("zk节点测试:"+zk_father);
 
        try{ 
            // 事务开始标记           
            results.sampleStart();
            // 创建子节点
            zk.create(zk_father+zk_children, zk_context.getBytes(),
                    Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            // 获取节点洗信息
            byte[] data = zk.getData(zk_father+zk_children, false, null);
//            System.out.println(new String(data));
            resultData = new String(data);
            if(null == resultData){
                results.setSuccessful(false);
                results.setResponseData("zk result is null",null);
                results.setDataType(SampleResult.TEXT);
            }
            results.setSuccessful(true);
        }catch(Exception e){
            results.setSuccessful(false);
            results.setResponseData(e.toString(),null);
            results.setDataType(SampleResult.TEXT);
            e.printStackTrace();
            return results;
        }finally{
            //标记事务结束
            results.sampleEnd();
        }
//        System.out.println("写入成功");
//        results.setSuccessful(true);
        results.setResponseData(resultData,null);//将数据打印到查看结果树当中
        results.setDataType(SampleResult.TEXT);
        return results;
    }

    /**
     * 测试结束方法,结束测试中的每个线程
     * 实际运行时,每个线程仅执行一次,在测试方法运行结束后执行,类似于Loadrunner中的End方法
     */
    
    public void teardownTest(JavaSamplerContext arg0) {
        try {
            zk.close();
            System.out.println("关闭");
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
 
}
    

代码及依赖包如下:

原文地址:https://www.cnblogs.com/leixiaobai/p/10245991.html