Redis-Backed Page Caching for WordPress
We’ve been testing our new Redis-based page caching plugin for WordPress these past few months, and today we’re happy to announce that we’ve open sourced it and deployed to all customer nodes here on Pressjitsu.
(Looking for Redis-backed Object Caching for WordPress?)
Our MySQL-based caching solution has worked really well for our customers so far, but we thought we could use the same ideas and take them even further with Redis — an extremely fast and flexible in-memory key-value store.
Installation and Configuration
The new plugin requires a little bit of extra configuration before it could be used, as well as a running Redis server and the Redis PECL extension. Both are likely to be available in pre-built packages for your favorite Linux flavor, for example in Debian/Ubuntu:
apt-get install redis-server php5-redis
After installing and activating the WordPress plugin, you’ll need to create a symbolic link to the advanced-cache.php dropin:
cd /path/to/wp-content ln -s plugins/redis-page-cache/advanced-cache.php advanced-cache.php
Finally, enable page caching in WordPress with a constant in wp-config.php:
define( 'WP_CACHE', true );
The plugin has quite a few configuration options and some interesting features. You can read more about them in the full documentation on GitHub. Don’t forget to read through the Redis server configuration and purging cache sections.
With Redis-based page caching, we’ve been able to solve some of the performance and maintenance issues we’ve had with our MySQL implementation. As a result, the same benchmark with our new plugin shows a 40% increase (10k vs 7k) in number of served requests in one minute with a 30% decrease in average response time (290ms vs 400ms):
Note that this includes an HTTPS handshake for every request — we’re big believers in SSL here at Pressjitsu. On a regular HTTP the same test has shown ~ 20k requests served in one minute with an average response time of 150 ms.
Eliminating the networking factor (speed and latency) between Loader.io’s servers and ours, on our 1G plan we’ve seen about 1000 successful requests per second with the popular ApacheBench utility, and with our short-term Nginx-based cache configuration designed to smoothen traffic surges, the number goes up to about 6000 successful requests per second.
What’s also interesting is how this change affected other resources. For example disk IO usage has dropped significantly, because unlike our previous MySQL implementation, Redis in our configuration does not use the disk at all:
The green line represents the disk IO, which in this case dropped from an average of 20 per second down to only 6. This graph was taken from a live website on our 1G plan with good cacheability, serving about 400k pageviews per month. If you’re wondering about the increase in average request size, that’s because MySQL is no longer performing frequent small requests to disk to retrieve our cache data.
PHP Response Times
The more interesting impact was on the overall upstream response times for PHP. This is due to the fact that PHP no longer touches MySQL when serving cached requests, which significantly increases InnoDB’s buffer pool efficiency for serving non-cache data.
The green line represents cache hits, while the blue line is for cache misses. While we’re happy we shaved off a few milliseconds off cache hits, but we’re more pleased that this allowed us to decrease response times for cache misses, in some cases up to 3 times faster!
Cache Hit Rate
One of the challenges we were faced with when moving to Redis is the total cache size — we no longer have the luxury of keeping as many cached items as we want and clean them up whenever because they’re no longer stored on disk.
With Redis we’re allocating a fixed and rather small amount of RAM (currently 32mb on our entry-level plans) for page caching, and if we outgrow that, Redis will evict older items to make room for newer ones on the fly. For WordPress sites with bad cacheability (remember PHP sessions?) this is bad business, much like any other caching solution. But for sites with good cacheability it’s not a problem at all.
To help deal with and debug cacheability, we’re also working on some CLI tools and commands for this new plugin that will output some stats and let users know about some cookie names and query variables they may want to ignore in their caching setup for a better hit rate. If you’re interested in testing out these tools here on Pressjitsu, please let us know via a support ticket and we’ll enable them for your server.
Why Not Persistent Object Caching?
It’s true that there are plenty of Redis-backed object caching plugins for WordPress, which can very well work with page caching solutions such as Batcache. But for many cases in-memory persistent object caching can actually hurt performance.
Plugins these days go crazy with options and transients and metadata, and with limited memory resources the cache backend can evict items developers wouldn’t expect it to. A simple “retrieve 10 latest posts” will result in 10 round trips to Redis for posts, another 10 for postmeta, another 10 or so for terms in addition to one MySQL query to retrieve the posh IDs. All of this versus just four MySQL queries without persistent object caching.
What’s worse is that if the object cache backend doesn’t have the requested items (which could have been evicted to make room for others), it could result in an additional 30 queries to MySQL. This is just one example.
We’re not saying persistent object caching is bad. It’s really good in targeted cases, where it’s being used on purpose, and not just slapped on. We do deploy persistent object caching for some customers that require it, but we can’t simply deploy it across the board and expect everyone’s performance to magically improve.
The Redis Page Cache plugin is distributed under the GPL and is available on GitHub, so bring on your pull requests! If you run into any problems or have any questions, please feel free to open an issue on GitHub or drop us a note on email@example.com.