JMeter完成java请求的压力测试详解以及问题总结

            作者:KK_Yolanda

        先定义一下我说的remoteService:即远程调用服务,没有http的url。不对外提供或者对外提供有限的服务。具体视各公司的代码架构所定,比如有些公司为web工程,scf服务,db。scf即为服务通讯框架(Service Communication Framework)该层结构,或者一些单独的lib包,里面集成了某些方法

对于有url的http请求,我们可以用jmeter的http请求进行压测,或者使用Apache-AB等进行测试,这种也可以用JMeter进行压力测试,具体操作如下

核心步骤


1.创建一个Java工程;

2.将JMeter的lib目录下的jar文件添加进此工程的Build Path;

3.创建一个类并实现JavaSamplerClient接口或继承AbstractJavaSamplerClient,并重写;



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



4.Export为Runnable Jar File;

5.将此jar包放入JMETER_HOME\lib\ext目录;

6.以管理员身份打开JMeter;

7.创建线程组、Java Request、查看结果树,进行测试;


一 创建java工程并实现JavaSamplerClient的重写


1新建一个Maven项目:File->new->Other->Maven Project




 

java压力测试 记录内存 cpu数值 工具 java项目压力测试_java


2  Next->Creat a simple project,使用Defaut路径->Next->Enter a group id for the artifact->填入Group Id 与package,此处与需要测试的RemoteService保持一致


3  在Eclipse下导入$\jmeter\lib\ext\下的所有jar包;导入额外的5个jar包,在$\jmeter\lib\ 下



java压力测试 记录内存 cpu数值 工具 java项目压力测试_初始化_02

java压力测试 记录内存 cpu数值 工具 java项目压力测试_jmeter_03


 


4  创建对应的Source Folder:src/main/java 和 src/main/resource


    src/main/java  编写代码


    src/main/resource 放配置文件(也可放在目录外,scf.config,此时打包放入jmeter使用时,配置文件在bin目录下,独立开来的)


    成品图如下



java压力测试 记录内存 cpu数值 工具 java项目压力测试_java请求测试_04

or

java压力测试 记录内存 cpu数值 工具 java项目压力测试_jmeter_05



java压力测试 记录内存 cpu数值 工具 java项目压力测试_java_06


5、创建class: JMeterSCFTest   将新建的类extends AbstractJavaSamplerClient 类。


 


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




几个方法都是什么意思呢:


1)、getDefaultParameters: 获取默认参数以及参数值


java压力测试 记录内存 cpu数值 工具 java项目压力测试_初始化_07


@Override
      public Arguments getDefaultParameters(){
            Arguments params = new Arguments();
            params.addArgument( "localPath", "1");
            params.addArgument( "catePath", "9224,13901");
            params.addArgument( "pn", "1");
            params.addArgument( "platform", "-1");
            params.addArgument( "referer", "referer");
            params.addArgument( "userAgent", "userAgent");
            params.addArgument( "ip", "1.1.1.1");
       return params;
      }


java压力测试 记录内存 cpu数值 工具 java项目压力测试_初始化_07


2)、setupTest: 测试方法运行之前的工作(初始化记录结果;从参数列表中获取对应变)


java压力测试 记录内存 cpu数值 工具 java项目压力测试_初始化_07


@Override
      public void setupTest(JavaSamplerContext arg0){ 
             results = new SampleResult();
             localPath = arg0.getParameter( "localPath");
             catePath = arg0.getParameter( "catePath");
             pn = Integer. parseInt(arg0.getParameter("pn"));
             platform = Integer. parseInt(arg0.getParameter("platform"));
             referer = arg0.getParameter( "referer");
             userAgent = arg0.getParameter( "userAgent");
             ip = arg0.getParameter( "ip");
      }


java压力测试 记录内存 cpu数值 工具 java项目压力测试_初始化_07


3)、runTest:运行测试方法(初始化记录结果,设定开始/结束记录时间,测试调用Service的主方法,测试成功与否的判断方法)  


java压力测试 记录内存 cpu数值 工具 java项目压力测试_初始化_07


public SampleResult runTest(JavaSamplerContext arg0){
     results = new SampleResult();//初始化记录结果
     results.sampleStart();//计时开始
     /*测试方法*/此处写自己的测试方法进行调用
     List<MingQiInfo> mingQiInfos = scf.loadMingQiInfo( localPath, catePath, pn, platform, referer, userAgent, ip);
     results.sampleEnd();//计时结束
     //判断测试成功与否的方法:可根据实际进行判断,此处为如果结果非空,则认为改次调用成功
     if (mingQiInfos!= null) {
          results.setSuccessful( true);
           for(MingQiInfo sssInfo :mingQiInfos){     //将结果写入结果树:在jmeter的监听器-查看结果树时即可查看返回结果         
               resultData += String. valueOf(sssInfo.toString());
      }
          results.setResponseData( "结果是:"+resultData ,null);
          results.setDataType(SampleResult. TEXT);
     }
     else {
          results.setSuccessful( false);//不满足判断条件则判为false,会出现在监听器-聚合报告的Error%列
     }
     return results;         
}


java压力测试 记录内存 cpu数值 工具 java项目压力测试_初始化_07


4)、tearDownTest:测试结束后的操作(这里什么也不做)


5)、其他参数:


//定义全局变量 
 
  
private    String    resultData    ; //写入结果树时使用     
  
private    SampleResult    results   ;
  
public   BrandMingQiTopService scf   getInstance().BMQSCF   ;    //调用remoteService的方法 
 
  

   //提供给jmeter的对外参数,可修改 
 
  
String    localPath   ;
  
String catePath;
  
int pn ;
  
int platform ;
  
String referer;
  
String userAgent; 
  
String    ip   ;


二 、打包,导出


1、右键点击项目:Export…


2、选择Java -> Runnable JAR file( 注意 :这里到处的是 runnable Jar,这样的话依赖的类也可以打进去。 强调下: 虽然必须有main方法,但实际在jmeter执行过程中 main方法不执行


3、在Launch configuration选择debug –【项目名称】



java压力测试 记录内存 cpu数值 工具 java项目压力测试_java请求测试_13


 


PS1:如果没有该选项可选:则执行一遍Run As-> Java Application 就有了。


PS2:如果没有main方法不能Run那么写一个和MySampleTest同级的class 放一个main函数进去调用一下刚刚写的MySampleTest这个类。然后Run As -> Java Application就好了,


public    class    debug {
  
public    static    void    main(String[] args) {
  
          jmtertest test =    new    jmtertest();
  
          JavaSamplerContext arg0 =    new    JavaSamplerContext(test.getDefaultParameters());
  
          test.setupTest(arg0);
  
          test.runTest(arg0);
  
          test.teardownTest(arg0);
  
exit(0);
  
     }


 


三、运行Jmeter


1、在$\jmeter\bin\下执行jmeter.bat


2、右键点击“测试计划”添加一个Thread Group(线程组)


3、右键点击线程组,添加一个Java Request


java压力测试 记录内存 cpu数值 工具 java项目压力测试_jmeter_14




4、点击该Java Request,可以看到之前我们新建的类MySampleTest


java压力测试 记录内存 cpu数值 工具 java项目压力测试_java_15


5、设定参数,双击可修改


6、右键线程组,添加一个聚合报告 


7、Ctrl+R运行测试计划,在聚合报告查看性能。


 


四  可能出现的问题:


问题1: 启动jmeter内存溢出:提示 An error occurred: PermGen space


java.lang.OutOfMemoryError: PermGen space. See log file for details.


更改内存设置,linux环境,修改jmeter.sh;windows环境,更改jmeter.bat文件,增大配置内存:
set HEAP=-Xmx1024m -Xms512m -Xmn256m -Xss128k //如果值太大,则jmeter会打不开,同时会有提示;值太小则有OutOfMemory的错误
set PERM=-XX:PermSize=64m -XX:MaxPermSize=128m -XX:+CMSClassUnloadingEnabled


问题2:监听器添加了聚合报告/查看结果树两个,测试结果特别不稳定。


‘View Result Tree’-查看结果树 在debug的时候非常的好用,但是也很占内存。所以在跑性能测试的时候还是不要用的为好。
1 占用内存:本来跑30分钟不到就有OutOfMemory的错误,把 ‘View Result Tree’ 这个listener删掉后,就再也没有出现
2 影响聚合报告的结果:写结果树占用时间和资源


问题3:执行debug程序时报错


检查下jmeter是否为中文路径,如果有,统一改成英文路径


问题4:配置文件获取不到或者失败,无法初始化


注意:在写初始化方法时,注意配置文件最好写成绝对路径;写成相对路径时,需要把配置放到jmeter对应的路径下。我比较习惯用相对路径“System.getProperty("user.dir")”,就需要把配置放到/jmeter/bin里面去。


问题5:调试一个问题时,我打印了初始化日志,发现每次鼠标点击“java请求”,都会初始化4次


初始化4次的解释:4个jmeter重载的函数,runTest setupTest getArgument tearDown,每个都会去初始化一次。
每次点击"java请求"都做初始化:是因为我在定义全局变量建立tcp连接时没有定义为"public static".
修改后解决。


问题6:非string型的变量怎么添加到参数里?


我定义了一个全局变量:int count;
在setupTest方法里设置“count = arg0.getParameter("count");”时提示
change type of 'count' to 'string'
解决办法:arg0.可以联想出来getIntParameter和getLongParameter用以添加不同的数据类型,count = arg0.getIntParameter("count"); 即 ok。


问题7:如何打印日志调试


重写getLogger方法,如:
 public org.apache.log.Logger getLogger()
	{  return super.getLogger();  }


使用:

this.getLogger().info(">>>>>>>>>> runTest() >>>>>>>>>>");这样就可以在jmeter日志里边打印出相关日志信息,见下图:

java压力测试 记录内存 cpu数值 工具 java项目压力测试_性能测试_16


问题8:定义Jmeter结果 results.setSuccessful(true)


SampleResult results=new SampleResult();
		results.setSampleLabel("Test2222");
		results.sampleStart();
		results.setSuccessful(true);
		results.sampleEnd();

如果没有设置results.setSuccessful() 默认执行结果是错误Error,所以这个可以更具逻辑判断来输出结果是正确或错误


问题9: 每次导出新的jar后,jmeter需要关闭后重新打开。


SampleResult results=new SampleResult();
		results.setSampleLabel("Test2222");
		results.sampleStart();
		results.setSuccessful(true);
		results.sampleEnd();

如果没有设置results.setSuccessful() 默认执行结果是错误Error,所以这个可以更具逻辑判断来输出结果是正确或错误,见下图:


java压力测试 记录内存 cpu数值 工具 java项目压力测试_java_17