8-10 2,729 views
最近需要对改造的redis缓存接口做压力测试,使用了开源压力测试工具JMeter,分享一下自己的使用经验,希望能对需要进行压力测试的开发同学有所帮助。
JMeter介绍
JMeter是Apache软件基金会下的一款开源压力测试工具,官方网址是:http://jmeter.apache.org/。JMeter可以测试静态、动态资源的性能,这些资源包括文件、Servlets 、Perl脚本、Java对象、数据库、FTP服务器等,并生成图形报告。JMeter使用Java开发,既支持可视化界面操作,也支持命令行操作。
Java请求测试(界面操作)
由于需要对改造的redis缓存接口测试,因此使用了JMeter的Java请求测试,安装和使用步骤如下所示(以Windows操作系统为例,并默认已安装、配置Java运行环境)。
1)从官网上下载JMeter并解压,例如解压至C:\apache-jmeter-2.9。
2)配置JMeter环境变量,增加变量JMETER_HOME,值为“C:\apache-jmeter-2.9”,修改变量CLASSPATH,增加“%JMETER_HOME%\lib\ext\ApacheJMeter_core.jar;% JMETER_HOME%\lib\jorphan.jar;%JMETER_HOME%\lib\logkit-1.2.jar;”
3)执行JMeter目录下的bin\jmeter.bat,显示JMeter界面说明安装成功。
4)新建Java工程,在该工程中,引入JMeter目录下lib中的jar包,继承JMeter的AbstractJavaSamplerClient类,在子类中重写setupTest、teardownTest、getDefaultParameters、runTest方法,实现对缓存接口的get、set、hGet、hSet方法进行测试,子类代码如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 |
package com.sohu.cms.test; 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 org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.sohu.cms.datacache.DataCache; import com.sohu.cms.datacache.DataCacheManager; /** * 继承jmeter的AbstractJavaSamplerClient类, * 重写setupTest、teardownTest、getDefaultParameters、runTest方法 * 对缓存接口的get、set、hGet、hSet方法进行测试 * @author wang * */ public class TestDataCacheClient extends AbstractJavaSamplerClient{ private static long start = 0; private static long end = 0; private static DataCacheManager dataCacheManager; private static DataCache dataCache; private static int size = 8192; private static String method = "get"; private static Object key = "TEST_KEY"; private static Object field = "TEST_FIELD"; private static Object value = new Byte[size]; //此处初始化我们改造的redis缓存接口dataCache static { ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"applicationContext.xml"}); dataCacheManager = (DataCacheManager) context.getBean("dataCacheManager"); dataCache = dataCacheManager.getObjectDataCache(); } /** * 测试开始 */ public void setupTest(JavaSamplerContext arg0) { start = System.currentTimeMillis(); } /** * 测试结束 */ public void teardownTest(JavaSamplerContext arg0) { end = System.currentTimeMillis(); System.out.println("[method=" + method + "] [size=" + size + "] [time:" + (end - start) / 1000); } /** * 添加参数默认值,参数默认值会在界面中显示 */ public Arguments getDefaultParameters() { //添加两个参数, //size为测试value值的字节大小,默认为8192字节 //method为需要进行测试的缓存接口方法,默认为get Arguments args = new Arguments(); args.addArgument("size", "8192"); args.addArgument("method","get"); return args; } /** * 测试 */ public SampleResult runTest(JavaSamplerContext arg0) { //获取界面或测试计划配置文件(jmx)中传入的参数 if (arg0.getParameter("method") != null) method = arg0.getParameter("method"); if (arg0.getIntParameter("size") > 0) size = arg0.getIntParameter("size"); value = new Byte[size]; SampleResult sr = new SampleResult(); try { boolean result = true; //根据传入的method参数测试相应的缓存接口方法 if (method.equals("get")){ //测试用例的核心逻辑 //测试用例开始 sr.sampleStart(); //测试用例执行 result = get(); //测试用例结果 sr.setSuccessful(result); //测试用例结束 sr.sampleEnd(); } else if (method.equals("set")) { sr.sampleStart(); result = set(); sr.setSuccessful(result); sr.sampleEnd(); } else if (method.equals("hGet")) { sr.sampleStart(); result = hGet(); sr.setSuccessful(result); sr.sampleEnd(); } else if (method.equals("hSet")) { sr.sampleStart(); result = hSet(); sr.setSuccessful(result); sr.sampleEnd(); } } catch (Exception e) { e.printStackTrace(); } return sr; } /** * 缓存接口get方法测试用例 * @return */ public boolean get() { boolean result = true; try { dataCache.get(key); } catch (Exception e) { System.out.println(e); result = false; } return result; } /** * 缓存接口set方法测试用例 * @return */ public boolean set() { boolean result = true; try { dataCache.put(key, value); } catch (Exception e) { System.out.println(e); result = false; } return result; } /** * 缓存接口hGet方法测试用例 * @return */ public boolean hGet() { boolean result = true; try { dataCache.hGet(key, field); } catch (Exception e) { System.out.println(e); result = false; } return result; } /** * 缓存接口hSet方法测试用例 * @return */ public boolean hSet() { boolean result = true; try { result = dataCache.hSet(key, field, value); } catch (Exception e) { System.out.println(e); result = false; } return result; } } |
5)将工程以jar包形式导出,置于JMeter目录lib\ext下,并将工程依赖的jar包置于JMeter目录lib下,启动JMeter。右键“测试计划”添加“线程组”。右键“线程组”添加“Java请求”,右键“Java请求”添加“聚合报告”。
6)在“Java请求”中选择所写的测试类,并可以设置相关参数,在“线程组”中可以设置并发线程数和循环次数,点击上方“启动”按钮开始测试,测试完成后,可以在“聚合报告”中查看到测试结果。
Java请求测试(命令行操作)
JMeter也支持命令行操作,在服务器上进行测试时,我们就采用了这种方式。一个简单的JMeter命令行操作如下所示(在JMeter目录bin下执行)。
Windows下: JMeter-n –t test.jmx -l result.jtl
Linux下: ./jmeter.sh -n –t test.jmx -l result.jtl
其中-n 表示命令行执行,test.jmx为测试计划配置文件,result.jtl为测试结果。
可在界面中进行测试计划配置,然后保存便可生成jmx格式文件,如下所示。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
<?xml version="1.0" encoding="UTF-8"?> <jmeterTestPlan version="1.2" properties="2.4" jmeter="2.9 r1437961"> <hashTree> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="测试计划" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> <boolProp name="TestPlan.functional_mode">false</boolProp> <boolProp name="TestPlan.serialize_threadgroups">false</boolProp> <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="用户定义的变量" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="TestPlan.user_define_classpath"></stringProp> </TestPlan> <hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="线程组" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="循环控制器" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <!-- 循环次数 --> <stringProp name="LoopController.loops">100</stringProp> </elementProp> <!-- 并发线程数 --> <stringProp name="ThreadGroup.num_threads">100</stringProp> <stringProp name="ThreadGroup.ramp_time">100</stringProp> <longProp name="ThreadGroup.start_time">1376103961000</longProp> <longProp name="ThreadGroup.end_time">1376103961000</longProp> <boolProp name="ThreadGroup.scheduler">false</boolProp> <stringProp name="ThreadGroup.duration"></stringProp> <stringProp name="ThreadGroup.delay"></stringProp> </ThreadGroup> <hashTree> <JavaSampler guiclass="JavaTestSamplerGui" testclass="JavaSampler" testname="Java请求" enabled="true"> <elementProp name="arguments" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" enabled="true"> <!-- 自定义参数 --> <collectionProp name="Arguments.arguments"> <elementProp name="size" elementType="Argument"> <stringProp name="Argument.name">size</stringProp> <stringProp name="Argument.value">8192</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> <elementProp name="method" elementType="Argument"> <stringProp name="Argument.name">method</stringProp> <stringProp name="Argument.value">set</stringProp> <stringProp name="Argument.metadata">=</stringProp> </elementProp> </collectionProp> </elementProp> <stringProp name="classname">com.sohu.cms.test.TestDataCacheClient</stringProp> </JavaSampler> <hashTree> <ResultCollector guiclass="StatVisualizer" testclass="ResultCollector" testname="聚合报告" enabled="true"> <boolProp name="ResultCollector.error_logging">false</boolProp> <objProp> <name>saveConfig</name> <value class="SampleSaveConfiguration"> <time>true</time> <latency>true</latency> <timestamp>true</timestamp> <success>true</success> <label>true</label> <code>true</code> <message>true</message> <threadName>true</threadName> <dataType>true</dataType> <encoding>false</encoding> <assertions>true</assertions> <subresults>true</subresults> <responseData>false</responseData> <samplerData>false</samplerData> <xml>false</xml> <fieldNames>false</fieldNames> <responseHeaders>false</responseHeaders> <requestHeaders>false</requestHeaders> <responseDataOnError>false</responseDataOnError> <saveAssertionResultsFailureMessage>false</saveAssertionResultsFailureMessage> <assertionsResultsToSave>0</assertionsResultsToSave> <bytes>true</bytes> </value> </objProp> <stringProp name="filename"></stringProp> </ResultCollector> <hashTree/> </hashTree> </hashTree> </hashTree> </hashTree> </jmeterTestPlan> |
result.ftl为按行输出的测试执行结果,如下所示,可在界面操作的聚合报告导入该文件从而生成聚合报告。
…
1376040889436,48,Java请求,,,线程组1-40,,true,0,0
1376040889792,9,Java请求,,,线程组1-7,,true,0,0
1376040889526,167,Java请求,,,线程组1-57,,true,0,0
1376040889791,10,Java请求,,,线程组 1-54,,true,0,0
…