通过jmeter测试Java性能

通过jmeter测试Java性能

对java与scala等代码或客户端的性能测试,不能直接发起http请求,需要实例化对象发送请求实现性能测试。

  1. jmeter提供的Java Request取样器可以控制实现JavaSamplerClient接口的类,输入参数并获取响应,利用多线程进行性能测试。
  2. 通过maven插件启动jmeter,配合部分插件管理依赖,简化每次测试环境的准备工作。

环境搭建

1. 搭建方式

手动配置环境:

  1. 创建测试项目
  2. 复制jmeter lib与lib\ext目录下的依赖文件添加到当前工程,如eclipse:鼠标选中工程点击右键 -> Build Path -> Configure Build Path -> 弹出框Libraries Tab -> 点击 Add External JARs -> 切换到待导入路径选取依赖jar
  3. 创建测试类实现JavaSamplerClient接口或继承AbstractJavaSamplerClient,并重写。 并不推荐使用实现接口的方式,使用集成AbstractJavaSamplerClient的方式比较好。
  4. 编译源码,导出为Runnable Jar File
  5. 编译后jar包放入jmeter lib\ext目录,项目依赖jar包放入jmeter lib目录,复制项目依赖配置文件
  6. 启动jmeter,创建测试计划进行测试。

通过maven构建配置环境:

  1. 创建测试项目
  2. 添加jmeter dependency
  3. 添加并配置插件:jmeter-maven-plugin(maven启动jmeter)、maven-dependency-plugin(copy依赖)、maven-dependency-plugin(打包项目并移动到制定目录)、maven-resources-plugin(copy项目依赖文件)
  4. 创建测试类实现JavaSamplerClient接口或继承AbstractJavaSamplerClient,并重写所需测试方法。
  5. 启动jmeter,创建测试计划进行测试。

上面两中方式启动jmeter测试都可以:

  • 手动配置环境:从命令行启动jmeter,将所有依赖都copy进jmeter项目,对于需要较大并发的分布式测试比较好,但是每次修改变动都需要重新打包copy。
  • 通过maven构建配置环境:在项目内启动jmeter,只需要在pom.xml中配置依赖,每次有修改重新构建并启动便可,但是分布式的测试仍然需要在分布机器上发送依赖包。

调试脚本与小并发的测试通过maven比较方便,在调试好之后将依赖分发到分布式机器上通过命令行启动agent。

2. maven配置

在maven的pom.xml文件中如下根据自己需要配置依赖文件和变量便可。

  • 依赖:org.apache.jmeter组织下添加的这三个依赖是编写Java Request扩展的必备。
  • jmeter-maven-plugin:maven项目中启动jmeter的插件。详细使用方法:插件配置官方文档
  • maven-dependency-plugin:maven构建依赖copy插件。
  • maven-antrun-plugin:ant插件,对编译后生成的文件再操作。
  • maven-resources-plugin:有些不是jmeter的配置依赖,在项目test/jmeter目录下无法自动copy到jmeter/bin目录下,使用这个插件copy。

注意:maven版本需要与插件兼容,如过不兼容jmeter插件是无法运行的,如jmeter-maven-plugin:2.9.0需要maven 3.6.0+

  1. <!-- 变量配置 --> 
  2. <properties> 
  3. <!-- version --> 
  4. <jmeter.version>5.0</jmeter.version> 
  5. <jmeter.maven.plugin.version>2.9.0</jmeter.maven.plugin.version> 
  6. <maven.dependency.plugin.version>3.1.0</maven.dependency.plugin.version> 
  7. <!-- 测试结果存放路径 --> 
  8. <jmeter.result.jtl.dir>${project.build.directory}/jmeter/results</jmeter.result.jtl.dir> 
  9. <!-- 测试报表存放路径 --> 
  10. <jmeter.result.html.dir>${project.build.directory}/jmeter/html</jmeter.result.html.dir> 
  11. </properties> 
  12. <!-- Java Request Sample依赖添加 --> 
  13. <dependencies> 
  14. <dependency> 
  15. <groupId>org.apache.jmeter</groupId> 
  16. <artifactId>ApacheJMeter_core</artifactId> 
  17. <version>${jmeter.version}</version> 
  18. </dependency> 
  19. <dependency> 
  20. <groupId>org.apache.jmeter</groupId> 
  21. <artifactId>ApacheJMeter_java</artifactId> 
  22. <version>${jmeter.version}</version> 
  23. </dependency> 
  24. <dependency> 
  25. <groupId>org.apache.jmeter</groupId> 
  26. <artifactId>jorphan</artifactId> 
  27. <version>${jmeter.version}</version> 
  28. </dependency> 
  29. </dependencies> 
  30. <!-- 构建插件 --> 
  31. <build> 
  32. <plugins> 
  33. <!-- jmeter插件 --> 
  34. <plugin> 
  35. <groupId>com.lazerycode.jmeter</groupId> 
  36. <artifactId>jmeter-maven-plugin</artifactId> 
  37. <version>${jmeter.maven.plugin.version}</version> 
  38. <executions> 
  39. <execution> 
  40. <id>jmeter-tests</id> 
  41. <goals> 
  42. <goal>jmeter</goal> 
  43. </goals> 
  44. </execution> 
  45. <!-- 设置ignoreResultFailures,必须把 jmeter-check-results加上--> 
  46. <execution> 
  47. <id>jmeter-check-results</id> 
  48. <goals> 
  49. <goal>results</goal> 
  50. </goals> 
  51. </execution> 
  52. </executions> 
  53. <configuration> 
  54. <!-- 指定jmeter版本 --> 
  55. <jmeterVersion>${jmeter.version}</jmeterVersion> 
  56. <!-- 聚合报告会覆盖generateReports,指定生成CSV结果 --> 
  57. <generateReports>true</generateReports> 
  58. <resultsFileFormat>csv</resultsFileFormat> 
  59. <!-- 设置忽略失败是否停止运行 --> 
  60. <ignoreResultFailures>true</ignoreResultFailures> 
  61. <!-- 设置结果文件末尾时间戳 --> 
  62. <testResultsTimestamp>true</testResultsTimestamp> 
  63. <!-- 时间戳格式 --> 
  64. <resultsFileNameDateFormat>Y-M-D H:m:s</resultsFileNameDateFormat> 
  65. <testFilesIncluded> 
  66. <!-- 指定运行的jmeter脚本 --> 
  67. <jMeterTestFile>JmeterTest.jmx</jMeterTestFile> 
  68. </testFilesIncluded> 
  69. <!-- 指定结果生成目录 --> 
  70. <resultsDirectory>${project.build.directory}/jmeter/results</resultsDirectory> 
  71. <!-- JVM参数 --> 
  72. <jMeterProcessJVMSettings> 
  73. <xms>2048</xms> 
  74. <xmx>4096</xmx> 
  75. <arguments> 
  76. <argument>-Xprof</argument> 
  77. <argument>-Xfuture</argument> 
  78. </arguments> 
  79. </jMeterProcessJVMSettings> 
  80. </configuration> 
  81. </plugin> 
  82. <!--复制copy依赖文件--> 
  83. <plugin> 
  84. <groupId>org.apache.maven.plugins</groupId> 
  85. <artifactId>maven-resources-plugin</artifactId> 
  86. <executions> 
  87. <execution> 
  88. <id>copy-resources</id> 
  89. <phase>package</phase> 
  90. <goals> 
  91. <goal>copy-resources</goal> 
  92. </goals> 
  93. <configuration> 
  94. <encoding>UTF-8</encoding> 
  95. <!--输出路径--> 
  96. <outputDirectory> 
  97. ${project.build.directory}/jmeter/bin 
  98. </outputDirectory> 
  99. <resources> 
  100. <resource> 
  101. <!--项目中的路径--> 
  102. <directory>${project.basedir}/src/test/jmeter/</directory> 
  103. </resource> 
  104. </resources> 
  105. </configuration> 
  106. </execution> 
  107. </executions> 
  108. </plugin> 
  109. <!-- copy被测项目依赖到指定目录 --> 
  110. <plugin> 
  111. <artifactId>maven-dependency-plugin</artifactId> 
  112. <version>${maven.dependency.plugin.version}</version> 
  113. <executions> 
  114. <execution> 
  115. <id>copy-dependencies</id> 
  116. <phase>package</phase> 
  117. <goals> 
  118. <goal>copy-dependencies</goal> 
  119. </goals> 
  120. </execution> 
  121. </executions> 
  122. <configuration> 
  123. <overWriteSnapshots>true</overWriteSnapshots> 
  124. <overWriteReleases>true</overWriteReleases> 
  125. <overWriteIfNewer>true</overWriteIfNewer> 
  126. <outputDirectory>${project.build.directory}/jmeter/lib</outputDirectory> 
  127. </configuration> 
  128. </plugin> 
  129. <!-- copy编译打包后jar文件到指定目录:由于jar是在编译完成之后才能拿到,所以用ant插件在编译后copy jar --> 
  130. <plugin> 
  131. <artifactId>maven-antrun-plugin</artifactId> 
  132. <executions> 
  133. <execution> 
  134. <phase>package</phase> 
  135. <goals> 
  136. <goal>run</goal> 
  137. </goals> 
  138. <configuration> 
  139. <tasks> 
  140. <mkdir dir="${project.build.directory}/jmeter/lib/ext"/> 
  141. <copy todir="${project.build.directory}/jmeter/lib/ext" overwrite="true" > 
  142. <fileset dir="${project.build.directory}" erroronmissingdir="false"> 
  143. <include name="*.jar"/> 
  144. </fileset> 
  145. </copy> 
  146. </tasks> 
  147. </configuration> 
  148. </execution> 
  149. </executions> 
  150. </plugin> 
  151. </plugins> 
  152. </build> 

测试例子

1. 项目编写

tess4j是Tesseract OCR API的Java JNA封装,除了准确性也可以测试一下处理速度。

  1. 新建maven项目。
  2. 添加tess4j maven依赖,jmeter依赖参考上面的maven配置添加
  1. <dependency> 
  2. <groupId>net.sourceforge.tess4j</groupId> 
  3. <artifactId>tess4j</artifactId> 
  4. <version>${tess4j.version}</version> 
  5. </dependency> 
  1. 创建工程目录如下:
JavaRequestDemo
├── JavaRequestDemo.iml
├── pom.xml
└── src
    ├── main
    │   ├── java
    │   │   └── Tess4jTest.java
    │   └── resources
    └── test
        ├── java
        └── jmeter
            ├── JmeterTest.jmx
            ├── jmeter.properties
            ├── reportgenerator.properties
            ├── saveservice.properties
            ├── system.properties
            ├── tessdata
            │   └── chi_sim.traineddata
            ├── upgrade.properties
            └── user.properties
  1. 下载训练库,下载地址, 不同语言的识别需要下载对应的训练库,这里下载中文的训练库chi_sim.traineddata,放置到src/test/jmeter/tessdata下
  2. test/jmeter可以放置项依赖的各种配置文件和jmeter的配置文件,会自动copy到编译后jmeter的bin目录
  3. 编写测试类Tess4jTest.java
  1. import net.sourceforge.tess4j.ITesseract; 
  2. import net.sourceforge.tess4j.Tesseract; 
  3. import net.sourceforge.tess4j.TesseractException; 
  4. import org.apache.jmeter.config.Arguments; 
  5. import org.apache.jmeter.protocol.java.sampler.AbstractJavaSamplerClient; 
  6. import org.apache.jmeter.protocol.java.sampler.JavaSamplerContext; 
  7. import org.apache.jmeter.samplers.SampleResult; 
  8. import org.apache.jmeter.testelement.TestElement; 
  9. import org.slf4j.Logger; 
  10. import org.slf4j.LoggerFactory; 
  11.  
  12. import java.io.File; 
  13. import java.util.Iterator; 
  14.  
  15.  
  16. /** 
  17. * public Arguments getDefaultParameters();设置可用参数及的默认值; 
  18. * public void setupTest(JavaSamplerContext arg0):每个线程测试前执行一次,做一些初始化工作; 
  19. * public SampleResult runTest(JavaSamplerContext arg0):开始测试,从arg0参数可以获得参数值; 
  20. * public void teardownTest(JavaSamplerContext arg0):测试结束时调用; 
  21. * */ 
  22. public class Tess4jTest extends AbstractJavaSamplerClient { 
  23.  
  24. public static void main(String[] args) { 
  25. Arguments arguments = new Arguments(); 
  26. arguments.addArgument("dataPath", "src/test/jmeter/tessdata1"); 
  27. arguments.addArgument("language", "chi_sim"); 
  28. arguments.addArgument("imagePath", "/tmp/20200119154923.jpg"); 
  29. JavaSamplerContext context = new JavaSamplerContext(arguments); 
  30. Tess4jTest test = new Tess4jTest(); 
  31. test.setupTest(context); 
  32. test.runTest(context); 
  33. test.teardownTest(context); 
  34. } 
  35.  
  36. private static final Logger LOG = LoggerFactory.getLogger(Tess4jTest.class); 
  37. // OCR 客户端 
  38. private ITesseract instance = new Tesseract(); 
  39. // The name of the sampler 
  40. private String name; 
  41. // Java Request参数 
  42. private String dataPath; 
  43. private String language; 
  44. private File image; 
  45.  
  46. /* 
  47. * setup操作,初始化参数 
  48. * */ 
  49. @Override 
  50. public void setupTest(JavaSamplerContext context) { 
  51. if (LOG.isDebugEnabled()) { 
  52. LOG.debug(whoAmI() + "\tsetupTest()"); 
  53. listParameters(context); 
  54. } 
  55. dataPath = context.getParameter("dataPath"); 
  56. language = context.getParameter("language"); 
  57. image = new File(context.getParameter("imagePath")); 
  58. name = context.getParameter(TestElement.NAME); 
  59. } 
  60.  
  61. /** 
  62. * 开始测试 
  63. * */ 
  64. @Override 
  65. public SampleResult runTest(JavaSamplerContext context) { 
  66. SampleResult sample = new SampleResult(); 
  67. sample.setSampleLabel(name); 
  68. // 
  69. /* 
  70. * dataPath一定要能访问否则jvm会异常退出,可以指定相对路径与绝对路径,可能只是提示异常: 
  71. * Failed to write core dump. Core dumps have been disabled. To enable core dumping, try "ulimit -c unlimited" before starting Java again 
  72. * 1. main函数中测试相对路径是相对于src的平级目录 
  73. * 2. jmeter中是相对于jmeter启动目录,maven插件是从bin目录启动,所以如果使用相对路径一般是copy到bin目录下 
  74. * */ 
  75. instance.setDatapath(dataPath); 
  76. instance.setLanguage(language); 
  77.  
  78. sample.setSamplerData(image.getAbsolutePath()); 
  79. try { 
  80. // 开始计时 
  81. sample.sampleStart(); 
  82. // 测试的主方法 
  83. String result = instance.doOCR(image); 
  84. // 设置结果 
  85. sample.setSuccessful(true); 
  86. sample.setResponseData(result, "UTF-8"); 
  87. } catch (TesseractException e) { 
  88. LOG.error("Tess4jTest error", e); 
  89. sample.setSuccessful(false); 
  90. sample.setResponseMessage(e.toString()); 
  91. } finally { 
  92. // 计时结束 
  93. sample.sampleEnd(); 
  94. } 
  95.  
  96. if (LOG.isDebugEnabled()) { 
  97. LOG.debug(whoAmI() + "\trunTest()" + "\tTime:\t" + sample.getTime()); 
  98. listParameters(context); 
  99. } 
  100. return sample; 
  101. } 
  102.  
  103. /* 
  104. * 参数设置获取 
  105. * */ 
  106. @Override 
  107. public Arguments getDefaultParameters() { 
  108. Arguments params = new Arguments(); 
  109. params.addArgument("dataPath", "tessdata"); 
  110. params.addArgument("language", "chi_sim"); 
  111. params.addArgument("imagePath", "/tmp/20200119154923.jpg"); 
  112. return params; 
  113. } 
  114.  
  115. /** 
  116. * 打印参数列表 
  117. */ 
  118. private void listParameters(JavaSamplerContext context) { 
  119. Iterator<String> argsIt = context.getParameterNamesIterator(); 
  120. while (argsIt.hasNext()) { 
  121. String lName = argsIt.next(); 
  122. LOG.debug(lName + "=" + context.getParameter(lName)); 
  123. } 
  124. } 
  125.  
  126. private String whoAmI() { 
  127. return new StringBuilder() 
  128. .append(Thread.currentThread().toString()) 
  129. .append("@") 
  130. .append(Integer.toHexString(hashCode())) 
  131. .toString(); 
  132. } 
  133. } 
  134.  
  1. 测试运行,直接运行Tess4jTest.java main方法

运行结果
运行结果

2. 运行测试

  1. 构建项目:mvn clean package
  2. 启动jmeter:mvn jmeter:gui
  3. 编写测试计划,单线程运行一下

测试代码
测试代码

测试结果
测试结果

多添加几个线程的聚合报告
多添加几个线程的聚合报告

posted @ 2020-01-19 19:04  二月的笔记  阅读(933)  评论(0编辑  收藏  举报