Over at Loadzen we’re constantly working to make load testing simpler by adding to the platform and extending the interface. This was made insanely easy by our adoption of django as a key platform (as has been written up before, the bulk of the site was actually written in django).
More importantly, we load tested Loadzen with itself (how meta).
Comprehensively load testing a django application means designing your tests to expose all the key layers of your site that could potentially cause a bottleneck.
In a django application these main areas are:
- The display layer – your HTML templates and rendering
- The logic layer – testing your views and ensuring they are not blocking and returning in a timely fashion
- The data layer – a common bottleneck with django applications is the ORM, and in turn, the Database
When you are designing your tests, it’s important to make sure you are testing each of these layers independently so as not to cause too much cross-contamination in your results.
The display layer
Any performance-oriented developer will tell you that the first place that you can squeeze performance out of your web application is in the templating / html rendering layer, mainly through the zealous use of caching.
This isn’t always possible, as many times in a django app you’ll use granular caching to only cache parts of your templates – and that means that you’ve wired part of your front end directly to your backend, exposing a direct line to something that could potentially break.
So, how do you test your display layer?
- Beat the hell out of your caching mechanism: be that memcached, a disk cache or django’s in-memory cache. In this case, enumerate your cached pages as your first scenario (but only the fully cached ones) to see how much strain your caching layer can handle.
- Once you have identified the cached pages, enumerate the partially cached ones and save them as a separate list, these pages have interactions with your server side logic and back-end, so you will want to test these independently to see if the components cause problems.
- Finally, identify the simpler database-output style views – these are low-complexity pages that pull data out of the database and show it to the user (think a shopping cart, or book details in a shop). These pages will test the read performance of your database as well as the rendering capability of your app.
The logic layer
You’ve already touched on this layer by enumerating and testing your basic data views, but to really identify the problems in the core of your application, you will need to identify the pages that perform the most operations on your data.
These pages / views will not be the ones that just display your data, they will make changes, compute and start other processes in your server.
These activities will usually take some form of input data, usually by form, or from a database lookup – so they can put stress on other components of your application by testing them, ideally though you will want to identify those user journeys that are the most processor-dependent, and in so doing, enumerate those journeys as their own lists and test them independently.
The data Layer
The final component of your application is your data layer, this will usually be exposed by forms and Ajax requests in your application.
Identifying these can be quite tricky (if your application is mainly XHR/Ajax based) or simple (if you expose many forms) – traditionally to test these elements you would try to send dummy data to your application – unfortunately most test tools will only let you post the recorded data.
At Loadzen we got around this problem by enabling our load generators to either take a CSV file of dummy data and loop through it, or to auto-generate random text for various types of form fields as part of the test, ideally getting around any caching that may exist in the object layer to really stress the application.
Once you have identified the user journeys / forms and actions that mostly expose your data layer, string these into a test set and identify the type of test data you would want to send into the application to really test your database and data logic.
One caveat with django – that can trip up any seasoned load tester is getting around Cross-Site-Request-Forgery tokens. These tokens are auto-generated by your django form to ensure that third-parties can’t flood your application with random spam.
Turning CRSF-protection off isn’t easy, but it can be done – it would be recommended with a django app to switch this off in your staging environment for the test, otherwise all of your POSTS will return errors.
Monitoring your app while you test
So here we’ve described some of the basics of really getting the most out of a load test and ensuring you really can stress test your website to the full, making it easy to identify where the bottlenecks are in your application without cross-contaminating your results too much.
However, none of this really matters if you can’t get the metrics from your application, some key apps and plugins to consider are:
- The django-debug-toolbar
- YSlow – this will help you diagnose your front end performance independently of the template rendering
- Django Snippetscream – will profile your code (middleware)
- Django-timelog – a handy little app to measure how long your app is spending on code
That was a whistle-stop tour around load testing a django application, as always – if you’re load testing your application, make sure you give us a try over at Loadzen, every test is free up to 25 concurrent users, which will give you enough to get you started profiling your app