Optimising WordPress for Performance
WordPress is a very powerful yet accessible platform. It powers many blogs and websites, including this one. However, many WordPress sites can often be slow to load and navigate. For a user, this is frustrating and will often result in them leaving the site and going elsewhere.
This isn’t WordPress’s fault per-se, a lot of optimisations are simply not possible out of the box because of the wide variety of hosting environments.
In this post, i’m going to explain the optimisations i’ve made to make this site load (reasonably) fast. It’s not the fastest site out there, but compared to an un-optimised version, it is several times faster. Some of the changes are more complicated than others and some will require more control over your hosting environment than you have available. However, even implementing a few of the simpler changes will still provide a performance boost.
One of the key methods for increasing performance is caching. Why have the server work several times to produce the same output to several users? Why not take the output that was generated for one user and serve it up to all of the users, so that the server only has to do the work of producing the page once?
Another key method is to decrease the delay in loading resources, including those which have been cached. It is several orders of magnitude faster to load something from memory than it is disk. Memory is cheap and plentiful these days, so it makes sense to store as much as possible in memory.
Finally, parallelisation. Whilst servers often have lots of memory these days, they also have a number of processor cores. If a number of tasks can be performed in parallel, then the overall processing time can be reduced.
Of course, these optimisation techniques are some of the most difficult things to achieve in computing. Thankfully though, many others have put a lot of hard work in to making tools and packages which achieve the previous optimisations, so with these methods in mind, here are the tools and packages that are responsible for serving up this site fast.
This post won’t delve in to the exact installation details of each as it will vary depending on your hosting environment and with time. However, a little bit of Googling will often reveal the instructions to install each in your specific situation. Hopefully this post can act as an overall guide on how to optimise performance and also why each change optimises performance.
nginx is a web server, similar to Apache. However, unlike Apache, nginx is designed to be high-performance, lightweight webserver. That isn’t to say Apache is bad, but nginx tends to perform better and is more scalable.
PHP, which is the scripting language used by WordPress, can be run in a number of ways, primarily as CGI, FastCGI or FPM. FastCGI and FPM both spawn pools of processes to run PHP code, improving performance. An important difference however is that FPM allows for a single cache to be used between all of the processes – there’s little point caching something if it’s not going to be shared after all.
The setup of php-fpm is a bit more involved than FastCGI, but the shared cache is definitely worth it. Additionally, there are two ways for the web server to communicate with php-fpm – over a TCP socket or a Unix socket. The latter is recommended as latency (and thus overall processing time) is reduced, but can be difficult to get working in a secure fashion.
Caching & Memory Storage
While nginx and php-fpm will help improve your performance in general, the real performance boost comes from caching and storing resources in memory.
PHP is an interpreted language. Thus, when a PHP script is run, the interpreter will convert the instructions to lower level code which is then run. The advantage of this is that new code can be deployed and run instantly, without the need to go through a compilation process. However, it means that the code will need to be interpreted and converted every time it is run.
However, it is possible to cache the output of the interpretation and save it for the next time the code is run, saving time subsequently. One popular way to achieve this in PHP was via the use of APC (the Alternative PHP Cache). However, with the release of PHP5.5, the ZendOpcache is now part of PHP’s standard distribution and is the recommended cache. Enabling it in a PHP5.5 installation is extremely simple and does not require any changes to existing PHP scripts – it’ll work against any PHP script out of the box as it is an OpCode cache. OpCode caches are a great way to get a quick, free performance boost without making any major changes.
Object Caching (Userland Caching)
The good news however is that a userland-only caching version of APC exists called APCu. Whilst not part of the standard PHP installation, it is available through most package managers and also PECL.
However, Object/Userland Caching will not work unless your PHP script specifically makes use of it. More on how to get WordPress to use your shiny new cache later on.
If you look at the HTML source for most sites, you’ll often see a nicely laid out document, with sensible human-readable formatting and naming. But why does your browser need to see pretty indentation? Everything could all be on one line and still perfectly parsable by a browser, but then the markup wouldn’t be readable to the designer who has to write the page.
As a compromise between human-readability for designers and minified files for parsing by the browser, we can use a minifier to transparently perform the process in between. However, the process isn’t free – your server will of course need to do some work to perform the minification. Thus, to see a performance boost from minification, having both an OpCode and Userland Cache is extremely important.
How do you perform the minification though? As before, more on this later.
Bringing it all together – adding support to WordPress
Several of the aforementioned features, such as Userland Caching, need the PHP script to be specifically adapted to take advantage of them. Without support in the PHP script, they won’t be utilised and no performance benefit will be realised.
WordPress by default does not provide support for many of these features as it needs to ensure maximum compatibility across a wide range of web hosting platforms. There’s nothing wrong with this and it is a good decision for the WordPress team to make.
However, a number of plugins are available which do add this functionality in to WordPress. The most notable is the W3 Total Cache. This plugin adds a huge number of caching options to WordPress and is highly configurable to almost any setup, supporting a wide range of backend caches.
If you have a low traffic blog (such as, sadly, this one), it’s important to remember that caches have a lifetime – and if the resources that are in the cache are not accessed within a certain time, they will be purged, meaning that they have to be generated and retrieved the next time someone requests them, wiping out any performance benefit you may have hoped to achieve. Increasing the cache lifetime is not a good idea – all resources should have a finite lifetime as they can and will change! Instead, you can ensure the cache is kept primed and ready by having an automated crawler access of all of the relevant resources. W3 Total Cache does have an option for this and it should definitely be enabled. Even with a high-traffic site, enabling this ensures that all users receive a consistently quick loading experience.
Now that you’ve implemented some or all of the above methods, how do you actually verify it’s working and that all your effort wasn’t for nothing?
Both the ZendOpcache and APCu offer the ability to see statistics relating to cache utilisation and also the contents of the cache. This helps you to verify that the cache is being used and that it is large enough to contain all of the content you wish to cache.
For ZendOpcache a number of scripts exist to check the cache status. I use opcache-status as it provides a single script that presents all of the relevant information in a clean, accessible format, other scripts are available though.
For APCu, a script is distributed with the installation which offers similar functionality. Check your distribution’s package as to where it might be, but under Ubuntu it can be found in /usr/share/doc/php-apc/apc.php.
The other way to test if everything is working is to simply load the website and examine the time taken to return the results. You can either use your browser’s developer tools to gather network statistics, or use a tool such as GTmetrix or Load Impact. GTmetrix is great for seeing how individual resources on your site load and what causes delay, whereas Load Impact is better suited for seeing how your site performs when lots and lots of people are accessing it at the same time.
Finally, if you’re minifying content, make sure you view the source of the page to ensure it actually has been minified!
Do keep in mind that if you’re logged in to your blog, W3 Total Cache won’t serve cached or minified pages to you. To see cached and minified pages, either log out or better, open up an Incognito browser window.
There’s a good reason why these changes are not available out of the box – they can be incompatible in a large number of environments and require extra setup which can put off a large number of potential users. With time though, the results can be impressive with load times that are several times quicker, and more consistent, than previously.
Despite the hard work to get some of these methods working, I hope that it has produced a noticeable benefit to your blog or site. Improving the performance of your site through these methods not only makes your site load faster, but crucially it helps serve your site up to more simultaneous users without an increase in hardware performance.
Good luck and happy optimising!