一般而言JMeter下性能最好的是jar包这类java原生请求,对于JMeter并没有原生支持的请求,一般都会将其直接编译为jar包,然后再JMeter中调用,这样性能最好。
但是有些需求并不适合用jar包的方式来进行,比如报文拼接,这个一般在请求Sampler发送前执行,比较方便的是使用BeanShell或者Groovy等前置处理器操作。那对于这种报文拼接的操作,使用JSR233组件还是BeanShell组件,以及使用JSR233组件中的BeanShell还是Groovy之间有没有什么性能差异呢?
我们去翻了翻JMeter官方的相关介绍,只在JMeter官网的最佳实践“http://jmeter.apache.org/usermanual/best-practices.html”中找到对JSR233组件有如下的描述:
强烈建议在大压力测试场景中使用Groovy这个可以预编译的语言,而BeanShell虽然也实现了预编译的接口,但是却没有被编码进去。这段介绍并没有说JSR233组件和BeanShell组件之间的性能差异。
下面我们就写三个简单的脚本来看一下在前置处理器中Groovy和BeanShell两种语言以及JSR233组件和BeanShell组件的性能差异。脚本截图如下,文章最下面放上jxm原文件。
Groovy和BeanShell的前置处理器中的代码非常简单,就是vars.put生成一个JMeter参数
每个脚本,我们设置为300VU,500TPS,执行5分钟,采用CLI方式执行,执行完后,切割中间的3分钟生成报告,服务器的硬件为8核CPUE7-4820。具体执行结果如下:
从试验结果可以得出如下几个很明显的现象:
-
JSR233组件下的BeanShell性能非常差。
-
同一个场景中,如果有的脚本使用了JSR233组件下的BeanShell语言,那会严重影响当前场景下的所有BeanShell组件模块的性能;同时也会稍微影响JSR233组件下的Groovy语言的性能,导致其TPS略有下降。
-
BeanShell组件下的BeanShell语言性能比JSR233组件下的Groovy语言性能稍差,实测TPS基本一致。
通过本次试验,在此提醒大家,在编写JMeter脚本的时候,千万不要使用JSR233组件下的BeanShell语言,如果要使用BeanShell语言一定要用BeanShell组件下的。
喜欢请长按下方二维码关注我的个人微信号,测试杂货铺。^_^
Groovy和BeanShell性能比较.JMX的源文件如下,复制然后保存成jmx就可以在JMeter中使用:
<?xml version="1.0" encoding="UTF-8"?> <jmeterTestPlan version="1.2" properties="5.0" jmeter="5.1 r1853635"> <hashTree> <TestPlan guiclass="TestPlanGui" testclass="TestPlan" testname="Test Plan" enabled="true"> <stringProp name="TestPlan.comments"></stringProp> <boolProp name="TestPlan.functional_mode">false</boolProp> <boolProp name="TestPlan.tearDown_on_shutdown">true</boolProp> <boolProp name="TestPlan.serialize_threadgroups">false</boolProp> <elementProp name="TestPlan.user_defined_variables" elementType="Arguments" guiclass="ArgumentsPanel" testclass="Arguments" testname="User Defined Variables" enabled="true"> <collectionProp name="Arguments.arguments"/> </elementProp> <stringProp name="TestPlan.user_define_classpath"></stringProp> </TestPlan> <hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group Groovy" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <intProp name="LoopController.loops">-1</intProp> </elementProp> <stringProp name="ThreadGroup.num_threads">300</stringProp> <stringProp name="ThreadGroup.ramp_time">10</stringProp> <boolProp name="ThreadGroup.scheduler">true</boolProp> <stringProp name="ThreadGroup.duration">300</stringProp> <stringProp name="ThreadGroup.delay"></stringProp> </ThreadGroup> <hashTree> <kg.apc.jmeter.samplers.DummySampler guiclass="kg.apc.jmeter.samplers.DummySamplerGui" testclass="kg.apc.jmeter.samplers.DummySampler" testname="DummyGroovy" enabled="true"> <boolProp name="WAITING">true</boolProp> <boolProp name="SUCCESFULL">true</boolProp> <stringProp name="RESPONSE_CODE">200</stringProp> <stringProp name="RESPONSE_MESSAGE">OK</stringProp> <stringProp name="REQUEST_DATA">${testvars1}</stringProp> <stringProp name="RESPONSE_DATA">Dummy Sampler used to simulate requests and responses without actual network activity. This helps debugging tests.</stringProp> <stringProp name="RESPONSE_TIME">${__Random(50,500)}</stringProp> <stringProp name="LATENCY">${__Random(1,50)}</stringProp> <stringProp name="CONNECT">${__Random(1,5)}</stringProp> </kg.apc.jmeter.samplers.DummySampler> <hashTree> <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="JSR223 PreProcessor" enabled="true"> <stringProp name="cacheKey">true</stringProp> <stringProp name="filename"></stringProp> <stringProp name="parameters"></stringProp> <stringProp name="script">vars.put("testvars1","testvars1Groovy")</stringProp> <stringProp name="scriptLanguage">groovy</stringProp> </JSR223PreProcessor> <hashTree/> </hashTree> <ConstantThroughputTimer guiclass="TestBeanGUI" testclass="ConstantThroughputTimer" testname="Constant Throughput Timer" enabled="true"> <intProp name="calcMode">2</intProp> <doubleProp> <name>throughput</name> <value>30000.0</value> <savedValue>0.0</savedValue> </doubleProp> </ConstantThroughputTimer> <hashTree/> </hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group JSR233BeanShell" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <intProp name="LoopController.loops">-1</intProp> </elementProp> <stringProp name="ThreadGroup.num_threads">300</stringProp> <stringProp name="ThreadGroup.ramp_time">10</stringProp> <boolProp name="ThreadGroup.scheduler">true</boolProp> <stringProp name="ThreadGroup.duration">300</stringProp> <stringProp name="ThreadGroup.delay"></stringProp> </ThreadGroup> <hashTree> <kg.apc.jmeter.samplers.DummySampler guiclass="kg.apc.jmeter.samplers.DummySamplerGui" testclass="kg.apc.jmeter.samplers.DummySampler" testname="DummyJSR233BeanShell" enabled="true"> <boolProp name="WAITING">true</boolProp> <boolProp name="SUCCESFULL">true</boolProp> <stringProp name="RESPONSE_CODE">200</stringProp> <stringProp name="RESPONSE_MESSAGE">OK</stringProp> <stringProp name="REQUEST_DATA">${testvars1}</stringProp> <stringProp name="RESPONSE_DATA">Dummy Sampler used to simulate requests and responses without actual network activity. This helps debugging tests.</stringProp> <stringProp name="RESPONSE_TIME">${__Random(50,500)}</stringProp> <stringProp name="LATENCY">${__Random(1,50)}</stringProp> <stringProp name="CONNECT">${__Random(1,5)}</stringProp> </kg.apc.jmeter.samplers.DummySampler> <hashTree> <JSR223PreProcessor guiclass="TestBeanGUI" testclass="JSR223PreProcessor" testname="JSR223 PreProcessor" enabled="true"> <stringProp name="scriptLanguage">beanshell</stringProp> <stringProp name="parameters"></stringProp> <stringProp name="filename"></stringProp> <stringProp name="cacheKey">true</stringProp> <stringProp name="script">vars.put("testvars1","testvars1BeanShell");</stringProp> </JSR223PreProcessor> <hashTree/> </hashTree> <ConstantThroughputTimer guiclass="TestBeanGUI" testclass="ConstantThroughputTimer" testname="Constant Throughput Timer" enabled="true"> <intProp name="calcMode">2</intProp> <doubleProp> <name>throughput</name> <value>30000.0</value> <savedValue>0.0</savedValue> </doubleProp> </ConstantThroughputTimer> <hashTree/> </hashTree> <ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" testname="Thread Group BeanShellBeanShell" enabled="true"> <stringProp name="ThreadGroup.on_sample_error">continue</stringProp> <elementProp name="ThreadGroup.main_controller" elementType="LoopController" guiclass="LoopControlPanel" testclass="LoopController" testname="Loop Controller" enabled="true"> <boolProp name="LoopController.continue_forever">false</boolProp> <intProp name="LoopController.loops">-1</intProp> </elementProp> <stringProp name="ThreadGroup.num_threads">300</stringProp> <stringProp name="ThreadGroup.ramp_time">10</stringProp> <boolProp name="ThreadGroup.scheduler">true</boolProp> <stringProp name="ThreadGroup.duration">300</stringProp> <stringProp name="ThreadGroup.delay"></stringProp> </ThreadGroup> <hashTree> <kg.apc.jmeter.samplers.DummySampler guiclass="kg.apc.jmeter.samplers.DummySamplerGui" testclass="kg.apc.jmeter.samplers.DummySampler" testname="DummyBeanShell" enabled="true"> <boolProp name="WAITING">true</boolProp> <boolProp name="SUCCESFULL">true</boolProp> <stringProp name="RESPONSE_CODE">200</stringProp> <stringProp name="RESPONSE_MESSAGE">OK</stringProp> <stringProp name="REQUEST_DATA">${testvars1}</stringProp> <stringProp name="RESPONSE_DATA">Dummy Sampler used to simulate requests and responses without actual network activity. This helps debugging tests.</stringProp> <stringProp name="RESPONSE_TIME">${__Random(50,500)}</stringProp> <stringProp name="LATENCY">${__Random(1,50)}</stringProp> <stringProp name="CONNECT">${__Random(1,5)}</stringProp> </kg.apc.jmeter.samplers.DummySampler> <hashTree> <BeanShellPreProcessor guiclass="TestBeanGUI" testclass="BeanShellPreProcessor" testname="BeanShell PreProcessor" enabled="true"> <stringProp name="filename"></stringProp> <stringProp name="parameters"></stringProp> <boolProp name="resetInterpreter">false</boolProp> <stringProp name="script">vars.put("testvars1","testvars1BeanShell");</stringProp> </BeanShellPreProcessor> <hashTree/> </hashTree> <ConstantThroughputTimer guiclass="TestBeanGUI" testclass="ConstantThroughputTimer" testname="Constant Throughput Timer" enabled="true"> <intProp name="calcMode">2</intProp> <doubleProp> <name>throughput</name> <value>30000.0</value> <savedValue>0.0</savedValue> </doubleProp> </ConstantThroughputTimer> <hashTree/> </hashTree> <ResultCollector guiclass="ViewResultsFullVisualizer" testclass="ResultCollector" testname="View Results Tree" enabled="false"> <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>true</fieldNames> <responseHeaders>false</responseHeaders> <requestHeaders>false</requestHeaders> <responseDataOnError>false</responseDataOnError> <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage> <assertionsResultsToSave>0</assertionsResultsToSave> <bytes>true</bytes> <sentBytes>true</sentBytes> <url>true</url> <threadCounts>true</threadCounts> <idleTime>true</idleTime> <connectTime>true</connectTime> </value> </objProp> <stringProp name="filename"></stringProp> </ResultCollector> <hashTree/> <ResultCollector guiclass="SummaryReport" testclass="ResultCollector" testname="Summary Report" 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>true</fieldNames> <responseHeaders>false</responseHeaders> <requestHeaders>false</requestHeaders> <responseDataOnError>false</responseDataOnError> <saveAssertionResultsFailureMessage>true</saveAssertionResultsFailureMessage> <assertionsResultsToSave>0</assertionsResultsToSave> <bytes>true</bytes> <sentBytes>true</sentBytes> <url>true</url> <threadCounts>true</threadCounts> <idleTime>true</idleTime> <connectTime>true</connectTime> </value> </objProp> <stringProp name="filename"></stringProp> </ResultCollector> <hashTree/> </hashTree> </hashTree> </jmeterTestPlan>