Table of Contents
What is JMeter ?
- Jmeter is a s functional testing tool for a web application, file server, web server and even database
- Is easy to configure and provides all needed tools to run HTTP load tests against any WebServer
Download and Install JMeter
Download Jmeter 2.13 from http://jmeter.apache.org/download_jmeter.cgin $ mkdir JMETER $ unzip apache-jmeter-2.13.zip $ pwd /home/oracle/JMETER/apache-jmeter-2.13/bin $ chmod 755 jmeter $ jmeter --> GUI should be started !
First JMeter Project
Add Users Edit > Threads(User) -> Thread Group Add HTTP Request Thread Group [ RC ] -> Add -> Sampler -> HTTP request Server Name : localhost Port Number : 8180 Path : /WFJPA2EL-1.0 Add Listener to display HTTP traffic Thread Group [ RC ] -> Add -> Listener -> View Results Tree Now Press Start and verify the HTTP traffic View Result Tree -> Traffic -> Click on a Single HTTP request There a 3 Viewing Options to display the test results - Sampler results - Request - Response data Details on above Viewing Option - Sampler Results Thread Name: Thread Group 1-1 Sample Start: 2015-06-09 08:30:58 CEST Load time: 29 Connect Time: 4 Latency: 6 Size in bytes: 4910 Headers size in bytes: 454 Body size in bytes: 4456 Sample Count: 1 Error Count: 0 Response code: 200 Response message: OK Response headers: HTTP/1.1 200 OK Connection: keep-alive X-Powered-By: Undertow/1 Set-Cookie: JSESSIONID=6RuYgEBp_dbe0VnE2S_8FWk2.wls1; path=/WFJPA2EL-1.0 Server: WildFly/8 Content-Type: text/html;charset=UTF-8 Content-Length: 4456 Date: Tue, 09 Jun 2015 06:30:58 GMT HTTPSampleResult fields: ContentType: text/html;charset=UTF-8 DataEncoding: UTF-8 - Request data GET http://localhost:8180/WFJPA2EL-1.0/ [no cookies] Request Headers: Connection: keep-alive Host: localhost:8180 User-Agent: Apache-HttpClient/4.2.6 (java 1.5) Thread Group [ RC ] -> Add -> Sampler -> HTTP request - Response Data [ The HTML document ! ] <?xml version='1.0' encoding='UTF-8' ?> <!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"><head id="j_idt2"> <title>Testing RAC - J2EE JPA2 API! </title> <style> .BGImage{ background-image: url("resources/images/1920x1200_night.png"); } </style></head><body class="BGImage"><table> <tbody> <tr> ... Add HTTP Cookie Manager and HTTP Cache Manager Thread Group [ RC ] -> Add -> Config Element -> HTTP Cookie Manager Thread Group [ RC ] -> Add -> Config Element -> HTTP Cache Manager HTTP Cache Manager -> simulates WEB Browser Caching HTTP Cookie Manager -> simulates Browser Cookie -> Click on HTTP cookie manager -> Uncheck Clear Coookies each Iteration With an enable HTTP Cookie Manager the request should look like GET http://localhost:8180/WFJPA2EL-1.0/ Cookie Data: JSESSIONID=dIV4Kg4Ge1672IoaR75GPWcW.wls1 Without an HTTP Cookie Manager the Request looks like: GET http://localhost:8180/WFJPA2EL-1.0/ [no cookies]
Recording a User Script With a Browser
For inital testing modify Thread Group : Number of Threads ( user ) : 1 Loop Count : 1 Use the Recording template File -> Templates -> Recording This creates a Test Plan with following major elements - User Defined Variables - HTTP Request Defaults - HTTP Cookie Manager - Thread Group - Recording Controller - View Results Tree - WorkBench - HTTP(S) Test Script Recorder - View Results Tree Verify HTTP(S) Test Script Recorder settings and start the Recorder --> Global Settings for Proxy Port : 8888 Go to the end of HTTP(S) Test Script Recorder Page and press << Start >> Prepare your WEBapplication by modify the Firefox Proxy Configuration Edit -> Preferences -> Advanced -> Network -> Settings -> Manuals Proxy Configuration HTTP Proxy : localhost Port : 8888 Remove Entries NO PROXY entries like : localhost, 127.0.0.1 Record the Session Start the initial HTTP GET request $ firefox http://localhost:8180/WFJPA2EL-1.0/ Now Press your GUI buttons to create the HTTP Post requests ! Review Recorded HTTP traffic under Thread Group -> Recording Controller -> 45 /WFJPA2EL-1.0 45 /WFJPA2EL-1.0 GET 46 /WFJPA2EL-1.0/ GET 47 /WFJPA2EL-1.0/faces/index.xhtml POST 48 /WFJPA2EL-1.0/faces/index.xhtml POST 49 /WFJPA2EL-1.0/faces/index.xhtml POST 50 /WFJPA2EL-1.0/faces/index.xhtml POST 51 /WFJPA2EL-1.0/faces/index.xhtml GET Now Replay the Recorded Session by pressing START and check the newly filled View Results Tree -> All POST request are failing with Error Count: 1 Response code: 500 Response message: Internal Server Error The HTTP GET request returns j_id1:javax.faces.ViewState:0" value="-3761271259220317840:-5309836328462799600" wheras the POST request sending back the old recorded ViewState variable javax.faces.ViewState=-4902608378562698912%3A-4211783223364451074 As you can see the ViewState variable returned from the HTTP GET request is different than the ViewState variable sent in the subsequent HTTP POST request. This is the root cause for getting Response code: 500 errors Fix : We need to extract the ViewState from the first GET request into a variable and arm our subsequent HTTP POST with that variable . Step 1: Extract the hidden Field ViewState into a Variable First Add a Debug Sampler Thread Group -> Add -> Sampler -> Debug Sampler Locate the ViewState value returned from the first HTTP GET request Thread Group -> View Result Tree [ Use the same HTTP requst ID as found in the Recording Controller output View Result Tree : 45 /WFJPA2EL-1.0/ Recording Controller : 45 /WFJPA2EL-1.0/ Copy from View Result Tree ( Use <ctrl>C and <ctrl>V for copy and paste ) the following Line : "j_id1:javax.faces.ViewState:0" value="-4364374341049834252:-7433662177008040460" autocomplete="off" Add regular Expression to extrace ViewState variable - Go the first HTTP GET request [ request 31 ] Recording Controller -> RC HTTP GET request -> Add -> Post Processors -> Regular Expression Extractor Reference Name : jsfViewState Regular Expression : input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="(.+?)" autocomplete Template : $1$ Default Value : DEFAULT-VALUE-NOT-EXPECTED Note we changed in the Regular Expression Extractor : ViewState:0" value="-4364374341049834252:-7433662177008040460" to ViewState:0" value="(.+?)" Now Replay and verify that Debug Sampler successfully extract the jsfViewState parameter View Result Tree -> Debug Sampler -> Response Data JMeterVariables: .. jsfViewState=8326703641583194307:-77748042595564357 jsfViewState_g=1 jsfViewState_g0=input type="hidden" name="javax.faces.ViewState" id="j_id1:javax.faces.ViewState:0" value="8326703641583194307:-77748042595564357" autocomplete jsfViewState_g1=8326703641583194307:-7774804259556435 -> jsfViewState variable is succesfully extracted from the HTTP GET request Step 2 : Replace all related POST request replace the ViewState Parameter with our extracted ${jsfViewState} Variable Goto Recording Controller click on the first POST Request wich is in our case : 32 /WFJPA2EL-1.0/faces/index.xhtml Scroll Down the Parameter Box and locate javax.faces.ViewState 7488737670588160729:2714299608714531806 true true Replace the value field 7488737670588160729:2714299608714531806 with our view state variable : ${jsfViewState} The complete record should now look like ; -> Note be careful and remove any spaces behind ${jsfViewState} declaration Repeat this step for all subsequent HTTP POST requests . Rerun the recorded session - all HTTP operation should be flagged green The last HTTP GET request reports in the Sampler Box : Thread Name: Thread Group 1-1 Sample Start: 2015-06-18 19:42:35 CEST Load time: 153 Connect Time: 0 Latency: 136 Size in bytes: 54033 Headers size in bytes: 0 Body size in bytes: 0 Sample Count: 1 Error Count: 0 Response code: 200 Response message: Number of samples in transaction : 5, number of failing samples : 0
Working with Assertions
Duration Assertion First lets have a look as the current statistics for out HTTP Post request by looking on out Summary Report Samples Avg Min Max Std. DEv Error Throughput KB/s 16 /WFJPA2EL-1.0/faces/index.xhtml 3 17 12 28 7.318 0.0 18.98 96.11 -> We don't have any errors and the Average Response Time is 12 ms Rerun test again and check Summary Report Add a Duration Assertion for the above HTTP Post with : 12 ms Samples Avg Min Max Std. DEv Error 176 /WFJPA2EL-1.0/faces/index.xhtml 15 13 11 28 4.02 0.066 -> 6,6 % of our requests shown some ERRORS View Test Results Double click on the red marked Request Assertion error: false Assertion failure: true Assertion failure message: The operation lasted too long: It took 13 milliseconds, but should not have lasted longer than 12 milliseconds. -> Here we get Details about our failed Request Add a response Assertion to a HTTP POST Recording Controller -> RC HTTP POST -> Add Assertions -> Response Assertion In this HTTP response we expect to find following test pattern : -> Suspend Transaction - Status: SUSPEND - Salary:1500 Reviewing a failed Response Assertion :
First Performance Tests
For last testing we are heavy business transaction doing the following : - HTTP Request1 : Request the inital page via HTTP GET request - HTTP POST Request2: Uses a HTTP post request to - Start a JTA transaction ( Not JTA transaction are always XA transactuons - Run JPA flush [ == Insert a new db record ] - Suspend the JTA transaction using the JEE TransactionManager API - Add JTA transaction object, Entity Manager object to our HTTPSession Object - HTTP POST Request3: Uses a HTTP post request to - retrieve JTA transaction object and Entity Manager object from our HTTPSession Object - Resume the Transaction and update the record - Commit the record - in case of any errors rollback the transacton - Cleanup HTTP session object , clear the Entity Manager - HTTP Request4: Uses a HTTP post request to - Invalidate the HTTP session For performance testing we modify our Thread Group : Number of Threads ( user ) : 5 Loop Count : 1000 This JMETER session will run 5.000 Business Transactions Note: Disable all Listeners for Throughput / Performance Testing as listeners are very CPU and Memory intensive . -> For the inital performance test we will run only using the Summary report Findings : - We are running 5.000 Transactions with a throughtput of 200 HTTP request per second - About 0.18 % of our HTTP requests are failing - The average duration of our HTTP post are between 30 and 59 ms As we get some errors we will add the View Results Tree. Because we are in a testing phase where we print errors and runtine information to the User screen the HTML will give us an easy way to get details about the error
Some Deatails about Listeners
Useful Listeners - Summary Report - Repsonse Time Graph - View Results in Table - View Results Tree Note Disable all Listeners for Throughput / Performance Testing as listeners are very CPU and Memory time intensive
Real Testing with RAC, JMeter and Virtaulbox
Test-Configuration 14:23:21.294 Calling getRacInfo() in progress ... 14:23:21.294 Hibernate Version: 4.3.7.Final 14:23:21.294 Driver Name : Oracle JDBC driver 14:23:21.294 Driver Version : 12.1.0.2.0 14:23:21.294 Database Product Version: Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production With the Partitioning, Real Application Clusters, Automatic Storage Management, OLAP, Advanced Analytics and Real Application Testing options 14:23:21.512 DB Name: BANKA 14:23:21.512 1. Instance Name: bankA_3 - Host: hract21.example.com - Pooled XA Connections: 32 14:23:21.513 2. Instance Name: bankA_1 - Host: hract22.example.com - Pooled XA Connections: 31 14:23:21.513 Leaving getRacInfo() without Exceptions ! All tests run on a single s Test Scenario - 10 Threads running a complex Transaction using suspend and resume 1000x - This translates to running 50.000 Transactions. Testcase Details - Using 2 datasources having MAX Connections set to 50 Datasource 1 is a JPA datasource and is used to operate on our JPA Entities Datasource 2 simulates a Normal datasource [ used as a tracking tool ] - Even we need to rollback our global transaction we need to write some log information before the ROLLBACK - The HTTP mentioned mentioned below are resp - HTTP POST request 1 : adds an Entity to the HTTP session object - HTTP POST request 2 : Starts the transaction running tm.begin() Calls em.flush() to store that record in our RAC DB asap Supspend the XA Transaction running tm.suspend() Logs some data via JDBC API and COMMITs that data [ this is possible as we have suspended our XA transaction ] Resume the transaction using tm.resume() Update our record running em.merge() Commit the data running tm.commit() Logs some data via JDBC API and COMMITs that data Configuration and Test details Host System: - Windows 8.1 - CPU i7-4710-HQ 2,5 GHz - 1 socket, 4 Physical CPus, 8 Logical CPUs - 16 Gbyte RAM Testcase - VirtualBox System I running : OEL 6.6, Wildfly 8.2 , 10 Threads ( running Jmeter ) - VirtualBox System II running : OEL 6.6, Oracle RAC 12.1.0.2.0 , Instance bankA1 - VirtualBox System III running : OEL 6.6, Oracle RAC 12.1.0.2.0 , Instance bankA2 - All VirtualBox System are configured to occupy a single physical CPU only What we exe expecting: - The testcase is CPU bound ( very little DB actions) - Our Host system running the Jmeter Threads should occupy about 100 % of our CPU. Single Core Testing - Verifiy CPU details on our JMeter VBox System Guest System [ OEL 6.6 ] details : [oracle@wls1 Desktop]$ nproc 1 [oracle@wls1 Desktop]$ lscpu Architecture: x86_64 CPU op-mode(s): 32-bit, 64-bit Byte Order: Little Endian CPU(s): 1 On-line CPU(s) list: 0 Thread(s) per core: 1 Core(s) per socket: 1 Socket(s): 1 NUMA node(s): 1 Vendor ID: GenuineIntel CPU family: 6 Model: 60 Stepping: 3 CPU MHz: 2496.669 BogoMIPS: 4993.33 L1d cache: 32K L1d cache: 32K L2d cache: 6144K NUMA node0 CPU(s): 0 -> Only a Single Physical CPU is active for our Virtualbox System running the Jmeter tests ! Jmeter test results : TaskManager Test results : Resource Manager test results: Test Summary: - No all CPU ticks available are used for our testing - This leads to a low TPS rate of 19.5 annd is far away from a real stress test Assumption : We assume that the VirtualBox System running the JMeter threads is limiting factor ! -> Let's add additonal CPU Power to the Virtualbos System Change VBox Configuration to use all 4 physical CPUs: Verify transaction rate using JMeter Output: Verify CPU Usage via Task Manager : Test Summary after changing Virtualbox Setup to use all phy. CPUs - Transaction rate increased from 19,6 TPS to 51,5 TPS - All CPUs are running at 100 % speed
Excelente explicación, llevaba buen rato buscando la explicación y aquí fue.
Muchas gracias.