Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

Difference between revisions of "RAP/LoadTesting"

< RAP
(Update to RAP 2.1 and later)
Line 23: Line 23:
 
=== Add HTTP Request Defaults ===
 
=== Add HTTP Request Defaults ===
  
=== Add a recording controller ===
+
=== Add a Recording Controller ===
  
 
The recording controller will contain the recorded requests
 
The recording controller will contain the recorded requests
Line 31: Line 31:
 
=== Add a Cookie Manager ===
 
=== Add a Cookie Manager ===
  
The cookie manager is required to ensure the same HttpSession in each request.
+
The cookie manager is required to ensure the same HTTP session in each request.
 +
If cookies are not working every request will create a new HTTP session and the server will return an HTTP error code.
  
 
''Add > Config Element > HTTP Cookie Manager''
 
''Add > Config Element > HTTP Cookie Manager''
  
 
The defaults are fine.
 
The defaults are fine.
 +
 +
Please note that there is a bug in JMeter 2.3.1 for clearing cookies for multiple runs / iterations; please use either JMeter 2.3.2 or later see [http://markmail.org/message/bis6om3wnpqtqin5]).
  
 
=== Add a Timer ===
 
=== Add a Timer ===
  
In order to configure the request interval, you have to add a timer. You might want to use a random timer to add some deviation to the interval. We recommend
+
In order to configure the request interval, you have to add a timer.
 +
Without a timer, every response is immediately followed by the next request, something a real user is not able to do.
 +
 
 +
You might want to use a ''random'' timer to add some deviation to the interval. This will lead to a better approximation of a real users behavior.
 +
We recommend
  
 
''Add > Timer > Gaussian Random Timer''
 
''Add > Timer > Gaussian Random Timer''
Line 66: Line 73:
 
== Running a test ==
 
== Running a test ==
  
* When running the tests with multiple threads you need to include an HTTP Cookie Manager (Please note that there is a bug in JMeter 2.3.1 for clearing cookies for multiple runs / iterations; please use either JMeter 2.3.0 or 2.3.2 see [http://markmail.org/message/bis6om3wnpqtqin5])
+
Once the test plan is configured and session is recorded, you can start the test by pressing the green ''Start'' button in the toolbar.
  
This is how the test plan should look like:
+
In the top right corner, you can observe the number of parallel sessions that are currently running.
  
[[Image:JMeterCookieManager.png]]
+
== Checking the Results ==
  
If cookies are not working every request will create a new session, this is not what we want to test (and leads to massive server load).  
+
To ensure that your recording is OK, you may want to start the test with only ONE session (configured in the Thread Group).
  
Also note the Gaussian Timer that has been added. A timer adds wait time between the requests, leading to a better approximation of a real users behaviour. If you don't add a timer you are putting a much higher load on the server, as every response is immediately followed by the next request, something a real user is not able to do.
+
=== Save Responses to Files ===
  
'''Generating <tt>requestCounter</tt>'''
+
By adding this element to your test plan you can ensure that the responses contain real JSON (not just errors).
 +
The first response will be HTML, all other responses JSON.
  
To make sure that we don't get the erros related to a wrong '<tt>requestCounter</tt>' value, add the following
+
''Add > Listener > Safe Responses to a File''
* A 'Response Assertion in the Thread Group for 'Main sample and sub-samples' with a Pattern Matching Rule 'contains not'
+
Multiple browser-instances
+
  
To generate the '<tt>requestCounter</tt>' parameter when replaying the request you have to add the following:
+
[[Image:JMeterSaveResponses.png]]
* A 'User Defined Variable' in the Thread Group with the name '<tt>request_counter</tt>' and the value '0'
+
* A 'Bean Shell Pre-Processor' in the Thread Group containing the following script
+
  var sampler = ctx.getCurrentSampler();
+
  if(sampler.getPath().contains("nocache")){
+
    var doCount = vars.get("startCounter");
+
    if(doCount == "OK") {
+
      oldCounter = Integer.parseInt(vars.get("request_counter"));
+
      sampler.addArgument("requestCounter", Integer.toString(oldCounter));
+
      newCounter = oldCounter + 1;
+
      vars.put("request_counter",Integer.toString(newCounter));
+
    }
+
  }
+
* Underneath the first request with a <tt>?nocache</tt> directive add a 'Bean Shell PostProcessor' with the following script
+
  vars.put("startCounter", "OK");
+
  
This is what it does:
+
Note that the target directory has to be present, it will not be created by JMeter.
* After the first post we set the flag 'startCounter' to 'OK' to start incrementing the <tt>requestCounter</tt> with every subsequent request.
+
* The Pre-Processor is called before every request. If it contains the <tt>?nocache</tt> directive it is a POST and must contain the '<tt>requestCounter</tt>' parameter
+
* The parameter ist added to the request with the <tt>sampler.addArgument</tt> call.
+
* The user variable is incremented for the next request
+
  
'''Check Playback'''
+
If you run the recording twice, the second pass should lead to the same pattern of responses as the first one.
  
This is how we check if the playback of the session is working.
+
== Configuration and Tuning Tips ==
* Start testing with only ONE session and two loops (configured in the Thread Group)
+
* Add a "Save Responses to a file" listener
+
* [[Image:JMeterSaveResponses.png]]
+
* Examine the response files, the patter should look like this
+
** The first response is an HTML file (expanded size is approxametly one megabyte, the compressed size that is going over the wire is about 200KB)
+
** The second response should be a .js or .javascript file with a size above 20KB, it contains the instructions for setting up the first user interface
+
** You may have responses that are of type "unknown" as responses to the UICallBack requests (can also appear as .js), in our example the third response
+
** The fourth response and all consecutive "non-UICallback" requests should have a response that contains some JavaScript instructions that do set some properties (e.g. w.setSpace or w.setItems in the example below)
+
<pre>org.eclipse.swt.EventUtil.suspendEventHandling();
+
var req = org.eclipse.swt.Request.getInstance();req.setRequestCounter( "7" );
+
var wm = org.eclipse.swt.WidgetManager.getInstance();
+
var w = wm.findWidgetById( "w44" );
+
w.setSpace( 0, 796, 19, 20 );
+
var w = wm.findWidgetById( "w81" );
+
w.setItems( [ "View I / Locate in browser view", "View I / Root", "View I / null"]);
+
qx.ui.core.Widget.flushGlobalQueues();
+
org.eclipse.swt.EventUtil.resumeEventHandling();</pre>
+
** if all responses contain only code like this, the test is not properly executed
+
<pre>org.eclipse.swt.Request.getInstance().send();
+
org.eclipse.swt.Request.getInstance().enableUICallBack( "rap",
+
"custom_service_handler",
+
"org.eclipse.rwt.internal.lifecycle.UICallBackServiceHandler" );
+
</pre>
+
** The second pass of the the test should lead to the EXACT same pattern of responses as the first one
+
** If this is not the case you need to turn on "Custom IDs" for the RAP widgets, an instruction will follow shortly
+
** After you verified the result pattern you should save only failed responses and turn up the volume of your load tests.
+
  
==Configuration and Tuning Tips ==
+
* Run JMeter and the server on different machines. JMeter causes significant CPU load as well.
  
* Tomcat / JVM
+
* Provide your application with enough heap. This depends on the number of active sessions and the memory consumption per session of your application.
** For best results monitor the memory consumption of your application. Turn on the garbage collector statistics to find out what is going on. If your application is leaking memory, performance will decrease very quickly!
+
 
** Provide your application with enough heap. This depends on the number of active sessions and the memory consumption per session of your application. For realistic results, use an appropriate session time out setting
+
* Choose an appropriate garbage collection strategy. We've found <tt>-XX:+UseConcMarkSweepGC</tt> to work best (on multi-core machines). The default garbage collector may lead to longer GC periods and can delay some responses drastically.
** Choose an appropriate garbage collection strategy. We've found <tt>-XX:+UseConcMarkSweepGC</tt> to work best (on dual-core machines)
+
 
** Start the JVM in server mode (<tt>-server</tt>)
+
* Start the JVM in server mode (<tt>-server</tt>)
** RAP can ensure that widget id's are generated in the exact same way from session to session. This comes at a slight performance cost. It is useful for load testing because, if id's are different between sessions, this could result in a server response that does not match what the test expects. To activate the 'repeatable id numbering scheme', download the <tt>org.eclipse.rap.widgetidgenerator</tt> plug-in from the RAP Sandbox (/cvsroot/rt/org.eclipse.rap/sandbox/org.eclipse.rap.widgetidgenerator) and deploy it with your application. Use <tt>-Dorg.eclipse.rwt.enableUITests=true</tt> in tomcat's launch arguments
+
 
** If you use tomcat, this servlet <tt>http://yourserver/manager/status/all</tt> provides interesting information
+
* If you use Tomcat, this servlet <tt>http://yourserver/manager/status/all</tt> provides interesting information
** Obviously - don't run JMeter and the Tomcat on the same machine
+
 
 +
* When running JMeter with many worker threads, you must increase it's heap size. It is advisable to start with a large initial heap size, to avoid delays resulting from additional heap allocation. Refer to the <tt>HEAP</tt> parameter in the <tt>jmeter</tt> script.
 +
 
 +
* Running JMeter with a GUI could slow it down. You can run JMeter in headless mode, using the command below. This runs testplan.jmx and saves the results to result.jtl. The result file can be opened with jmeter after the test run is finished. A large result file takes some time and memory to open - be patient and increase the heap. Warning: interrupting a test run in progress, will create an incomplete result file that cannot be opened!
  
* JMeter
 
** When running JMeter with many worker threads, you must increase it's heap size. It is advisable to start with a large initial heap size, to avoid delays resulting from additional heap allocation. Refer to the <tt>HEAP</tt> parameter in the <tt>jmeter / jmeter.bat</tt> scripts
 
** Running JMeter with a GUI could slow it down, since updating the GUI takes away CPU cycles. You can run jMeter without a UI, using the commandline below. It starts jmeter without a UI, runs testplan.jmx and saves the results to result.jtl. The result file can be opened with jmeter after the test run is finished. A large result file takes some time and memory to open - be patient and increase the heap. Warning: interrupting a test run in progress, will create an incomplete result file that cannot be opened!
 
 
<pre>./jmeter -n -t /home/elias/testplan.jmx -l /tmp/result.jtl</pre>
 
<pre>./jmeter -n -t /home/elias/testplan.jmx -l /tmp/result.jtl</pre>
  
Line 156: Line 118:
 
I was able to run the test with the url rewriting. In JMeter there is something called regular expression extracter. I used this to extract the jsessionid from the first response from the server and then pass the same id in the all the other requests.
 
I was able to run the test with the url rewriting. In JMeter there is something called regular expression extracter. I used this to extract the jsessionid from the first response from the server and then pass the same id in the all the other requests.
 
</blockquote>
 
</blockquote>
 
==Troubleshooting==
 
* Multiple Browser instances
 
** Problem: The only response data you get looks like this:
 
<pre>
 
qx.core.Init.getInstance().getApplication().reload( "Multiple browser-instances or
 
browser-tabs per session are not\nsupported. You may click OK for restarting the session." )
 
</pre>
 
** Solution: You likely didn't get a new session on recording but rather reused an old one. This reflects in the parameter <tt>requestCounter</tt> that is sent with each HTTP request. When recording, instead of reloading the application in an existing browser tab you need to load the page in a new browser tab or window.
 
** Follow the advices in the Recording section to be able to generate a fresh <tt>requestCounter</tt> value for each request
 
  
 
[[Category:RAP]]
 
[[Category:RAP]]

Revision as of 11:04, 20 February 2014

This article describes load testing / stress testing of RAP applications with Apache JMeter.

This Introduction (PDF) is very useful for getting started with JMeter.

Preparation

JMeter allows to record tests by adding a proxy to your browser and simply record the user interactions with the server.

  • Start JMeter
  • There are two in the tree, called Test Plan and WorkBench
  • Add a thread group to the Test Plan.

Add a Thread Group

The Thread Group will contain your recorded requests.

Select Add > Threads (Users) > Thread Group from the context menu.

Configure at least these settings:

  • Number of Threads (users): this is the number of sessions that will in run in parallel
  • Ramp-up Period (in second): the time it takes until the last session is started

Add HTTP Request Defaults

Add a Recording Controller

The recording controller will contain the recorded requests

Add > Logic Controller > Recording Controller

Add a Cookie Manager

The cookie manager is required to ensure the same HTTP session in each request. If cookies are not working every request will create a new HTTP session and the server will return an HTTP error code.

Add > Config Element > HTTP Cookie Manager

The defaults are fine.

Please note that there is a bug in JMeter 2.3.1 for clearing cookies for multiple runs / iterations; please use either JMeter 2.3.2 or later see [1]).

Add a Timer

In order to configure the request interval, you have to add a timer. Without a timer, every response is immediately followed by the next request, something a real user is not able to do.

You might want to use a random timer to add some deviation to the interval. This will lead to a better approximation of a real users behavior. We recommend

Add > Timer > Gaussian Random Timer

  • Open the context menu on WorkBench, and select Add > Non-Test Elements > HTTP(S) Test Script Recorder (in older versions this was called HTTP Proxy Server)

This is basically a proxy server that listens on a local port (8080 by default).

You should exclude static resources from the recording. Add a regular expression to the section URL Patterns to Exclude, e.g. .*\/rwt-resources\/.*

Recording a test

  • Configure your browser to use a proxy. Use localhost and the port you configure in the test recorder (8080 by default).
  • Start the proxy server: press the Start button at the bottom HTTP(S) Test Script Recorder page.
  • Open a new browser tab and load the URL of your application
  • Note: In RAP versions prior to 2.1, you had to re-start the browser before recording a test in order to ensure the parameter requestCounter started from zero.

Remove ServerPush Requests

After recording your test, you need to eliminate all requests with parameter servicehandler = org.eclipse.rap.serverpush. Usually, these are all requests without a cid parameter in the URL.

These requests are not answered by the server and will lead to blocking.

Running a test

Once the test plan is configured and session is recorded, you can start the test by pressing the green Start button in the toolbar.

In the top right corner, you can observe the number of parallel sessions that are currently running.

Checking the Results

To ensure that your recording is OK, you may want to start the test with only ONE session (configured in the Thread Group).

Save Responses to Files

By adding this element to your test plan you can ensure that the responses contain real JSON (not just errors). The first response will be HTML, all other responses JSON.

Add > Listener > Safe Responses to a File

JMeterSaveResponses.png

Note that the target directory has to be present, it will not be created by JMeter.

If you run the recording twice, the second pass should lead to the same pattern of responses as the first one.

Configuration and Tuning Tips

  • Run JMeter and the server on different machines. JMeter causes significant CPU load as well.
  • Provide your application with enough heap. This depends on the number of active sessions and the memory consumption per session of your application.
  • Choose an appropriate garbage collection strategy. We've found -XX:+UseConcMarkSweepGC to work best (on multi-core machines). The default garbage collector may lead to longer GC periods and can delay some responses drastically.
  • Start the JVM in server mode (-server)
  • When running JMeter with many worker threads, you must increase it's heap size. It is advisable to start with a large initial heap size, to avoid delays resulting from additional heap allocation. Refer to the HEAP parameter in the jmeter script.
  • Running JMeter with a GUI could slow it down. You can run JMeter in headless mode, using the command below. This runs testplan.jmx and saves the results to result.jtl. The result file can be opened with jmeter after the test run is finished. A large result file takes some time and memory to open - be patient and increase the heap. Warning: interrupting a test run in progress, will create an incomplete result file that cannot be opened!
./jmeter -n -t /home/elias/testplan.jmx -l /tmp/result.jtl

URL rewriting instead of cookies

From [2]:

I was able to run the test with the url rewriting. In JMeter there is something called regular expression extracter. I used this to extract the jsessionid from the first response from the server and then pass the same id in the all the other requests.

Back to the top