One of the most important things to know while launching web applications is under which amount of load it will crash. Every server has its limits. Not knowing what those limits are, can cause a lot of damage to your company’s image.
Before launching a new version of your project, it is recommended to run some load tests on the application. The results of these tests will tell you how much simultaneous visitors your application can handle in its current infrastructure and which server resource is most likely to crash first.
By knowing how much simultaneous users your application can handle, you can alter the configuration of the servers to make sure the infrastructure can handle the predefined number of visitors. You can add alerts to specific thresholds so that you have the time to scale up when your application needs additional resources. By being aware of the limits of your application, you can adjust to an increase of traffic.
How can I create load tests?
The first thing you will need to do before creating load tests is specifying test scenario’s. An important part of determine these scenario’s is knowing the visitor’s behavior in the website. For new sites, this can be a calculated guess. For existing websites, you can fetch this information from tools like Google Analytics.
For example: when you create an average web shop, you can split up your traffic in following scenario’s:
- 20% Homepage
- 20% Landing page visitors
- 20% Catalog / product page visitors
- 20% Searching visitors
- 20% Ordering visitors
While running the load test, the traffic is spread across these scenario’s. This will give you a real-life spread of load on the application.
Once you specified the scenario’s above, it is time to write the load tests. Our weapon of choice is JMeter. Internally the tool stores its configuration in an XML format. Fortunately, there is also a GUI provided which makes it easy to configure the test suites. You can imagine JMeter as a curl workflow tool on steroids. JMeter project consists of following main elements:
- Test plan: Contains user defined variables like environment, path, …
- Thread groups: Is comparable to a test suite
- Config elements: You can add tools that simulate cookie managers, browser cache, …
- Controllers: A controller consists of samplers and can contain logic like if, while, …
- Sampler: This will execute the HTTP requests.
- Pre-processor: Will perform advanced stuff like URL rewriting before sending the request.
- Post-processor: Collects data from a response. You can for example parse JSON or fetch form values based on CSS selector path.
- Assertions: Validates if a response contains the value it expects to be available.
- Listeners: Listeners are mostly used to display reports and graphs.
- Timers: You can specify random wait times between requests.
With the blocks above you can build up the test scenario’s you determined before. An example can look like this:
As you can see, in this testing scenario we will load the Google homepage and check if the response contains the word “Search”. We will also store a fictional CSRF token from the form in a variable by using a XPath extractor. By adding a cache and cookie manager, we are simulating an actual browser. When the test scenario contains a second request, it will serve the stored images directly from cache instead of loading them from the remote server.
On which environment should I run my load tests?
To get the best idea on how much traffic your infrastructure can handle, it is best to run these tests on the production system. You can try to find a moment on which there is not much traffic on the website and do it during those hours. When this is not possible, it is recommended to set up a duplicate environment with exactly the same resources. It is possible to downgrade the resources, but then you won’t know at which amount of connections the application will crash. An advantage of downgrading the resources is that you can find the weakest service with less effort.
How do I run my load tests?
One of the downsides of JMeter is that it runs on the system it is installed on. Therefor you are limited to the resources of your computer or the bandwidth of your network. You can imagine that this won’t be sufficient to detect the boundaries of your system. That is why we will need to run the tests through a distributed network of visitors.
One of the services that provide distributed visitors for load testing is BlazeMeter. You can create a new load test on BlazeMeter and upload the JMeter configuration file. Next, you can specify on which location you want to run the test. Possible options are AWS, Google Compute or Microsoft Azure. Next you can specify how many simultaneous users you want to simulate. You can spread them across multiple threads and multiple physical engines. Note that the number of users is multiplied by the amount of threads in your JMeter project. Finally, you can choose how long you want to run the test or how many iterations that should be executed. The configuration can look like this:
After running the load tests, you get a broad variety of results. For the test specified above, the result can look like this:
Off course, these results are not very accurate: Google won’t notice 10 additional users on their system. However, it gives you an idea of what the load results look like. Besides these statistics, it is possible to generate your own statistics with the monitoring tools you like to use. For example: There is a New Relic plugin available to link the data from the load test with the data from New relic.
How can I monitor my server resources?
As you can see, the statistics from New Relic contain information about the response time, amount of errors and generic statistics like that. If you want to know how the load is infecting your infrastructure, you must enable additional resource logging during the load test.
During the tests, we monitor the server processes with the top command. We also install New Relic on the machine’s so that we can generate advanced system statistics afterwards. This way it is possible to display advanced metrics like: CPU usage, memory usage, network traffic, application error rate, mysql errors, … during the load test.
Of course, it is possible that the performance issues are related to slow code in your application. The Transactions section in New Relic will display the top 10 slowest pages with their stack traces. This way, you can quickly detect which code is causing the slow response times. You can improve the code or add some caching and run the load tests again. If you go one step further, you can add automated Blackfire tests for this specific scenario to make sure that part of the code won’t ever slow your application down again.
In New Relic, it is possible to create custom load dashboards. If you frequently run load tests on your system, you can use this dashboard as a reporting tool. This will make it possible to run load tests and report the results in a couple of hours. The dashboard can also be used to monitor real-life traffic on your application.