Persistent Object Caching

cache-invalidation


ryan-hellyer
This post was contributed by Ryan Hellyer. He is from New Zealand, lives in Germany, and works as a full-time WordPress geek for Forsite Media in the Netherlands. He spends his time building WordPress plugins and getting up to mischief in his adopted home of Berlin.


I have an issue with WordPress caching plugins. It’s not that I don’t like using them, or that they’re junk (most are, but that’s a separate issue). No, the problem is that most people don’t have the foggiest idea how WordPress handles caching internally, and what causes their site to run faster.

Static page caching

Most caching plugins do what is called static page caching. They cache a complete page, including all of it’s HTML. This is terrific, as it means that WordPress doesn’t need to regenerate the page every time someone visits it, but it means that those pages will be out of date sometimes when content is updated. Anyone who has used these plugins can usually attest to cursing at their site due to to the cache not updating when required.

Object caching

For a very long time, WordPress has had a caching system baked into it. Most WordPress developers I’ve met have no idea this exists. Some have used transients, which are a part of the WordPress caching API, but in my experience, very few developers properly understand how they work.

By default, WordPress includes an internal caching system. If you use get_option( ‘something’ ); somewhere in your site, then run that same code later on in that page, WordPress will only need to load the data from the database once, as it caches it for use later on in the page load. It does this via the wp_cache_add(), wp_cache_set() and wp_cache_get() functions.

Transients behave in a similar way, but by default can store the data for use in subsequent page views by storing them in the database. Storing information in the database is resource intensive though, so transients must be used sparingly to avoid hammering the database too hard and actually causing the site to slow down rather than speed up.

What we need is the ability to store information in a persistent way (for use on more than the current page load), which can be written to and from extremely rapidly (unlike caching in the database).

Persistent object caching

Although the object caching system in WordPress was designed to only work on a single page load by default, the smart folks on the WordPress core team ensured that it was trivial to plug into this and provide a way to store data however you want and for as long as you want. Awesome!

A normal WordPress plugin cannot be used to provide persistent object caching in WordPress. You need to manually create a drop-in file called object-cache.php, which sits in the wp-content folder. Some of the larger (bloated?) plugins, will automatically generate this drop-in file in your wp-content folder.

Once installed, the object caching drop-in will cache anything utilizing the WordPress caching API. This includes transients, which will automatically stop using the default database layer and instead make use of whatever object caching back-end is available.

Some of the earlier implementations of object-cache.php files for WordPress simply stored the data in the database, or in flat static files. But there are a multitude of better backends/places to store small pieces of data like this, and there are many different object caching drop-ins available for WordPress to hook into these various systems.

In-memory data stores – ninja fast data storage

MySQL is fast, but nothing compares to just throwing some data into RAM for maximum performance. With this in mind, many people who are much smarter than I, have developed systems for allowing us to store random bits of data in the server’s RAM. The most popular of these is Memcached, but there are others including APC and Redis which are very popular. Since they store their data in RAM (when possible) and are designed to be fast rather than reliable, they are insanely fast at both data storage and retrieval.

With a database or flat file caching back-end, you can not refresh your cache rapidly, or store tiny bits of data. With an in-memory data store, those problems do not exist. For this reason, use of an in-memory data storage back-end can provide an enormous performance advantage to sites using them in conjunction with the WordPress object caching API.

To make use of one of these, simply ensure that Redis, Memcached or APC are installed on your server, then install one of their corresponding drop-in files (you have to get the correct one or all hell will break loose).

Once you have an appropriate object caching drop-in installed, you should notice an immediate increase in performance. WordPress caches a lot of data internally and none of that will need to be queried on every page load.

It is entirely normal to see a stock WordPress installation go from 20+ MySQL queries per page down to 4 queries, as the object caching backend takes care of storing all of the data which does not change between page loads. The WordPress API always attempts to refresh the cache when required; there are some instances in which this does not work perfectly, but it is usually a flawless cache refreshing process.

Faster static page caching

There are ways to serve and refresh static page caching plugins via the WordPress object caching system too, including via the Batcache plugin, provided by the kind folks at Automattic. This is beyond the scope of this blog post, but it is worth investigating if you also require static page caching.

Conclusion

Caching within WordPress is complex. Object caching is a vital tool for your toolbox, as it can provide a huge performance improvement without requiring you to resort to full page caching.

38

38 responses to “Persistent Object Caching”

    • If my understanding is correct, that’s a little different as it seems to combine static page caching with the object cache. It’s like running Batcache in combination with a Redis object cache plugin. It also requires hacking a core file to make it work, which I don’t think that would give any real benefit over simply using object-cache.php and advanced-cache.php drop-in files.

      Have you compared the performance to other setups? I’d be interested to hear if it’s possible to measure any benefit.

      I’m currently rebuilding my own server to use Redis object caching, but I’m intending to use Nginx page caching since it’s a bit more performant than routing that side of things through WordPress.

  1. This article was written by a true WordPress developer, completely ignoring everything from the visitor perspective. Persistent object caching is a good thing, but it isn’t going to be as fast as full-page caching, ever. If the author considers most “static page” caching plugins junk, he should offer one that isn’t.

    Visitors don’t care how a page is served, only that it’s served quickly. Any plugin or script that completely fulfills that criteria shouldn’t be written off as worthless. I agree most of them are bloated, but that’s only because of how many different web server configurations exist.

    • I never said not to use a static page cache. This post is about object caching though, so offering advice about static page caching would be quite out of place here. I did mention Batcache though, which I currently use myself. I am intending to switch to Nginx page caching soon though.

      • Perhaps it was the way you wrote it. It seemed to imply you didn’t like static page caching.

        On the subject of Nginx page caching, you may be better off using WP Super Cache. Nginx page caching is fast, but then you have to have a method of purging, which requires yet another plugin (and the purge module built into Nginx).

        • Nope, I definitely wasn’t intending to imply that static caching is bad. I was just trying to point out that things are not as simple as just mindlessly plugging in the caching plugin with the most fancy bells and whistles.

          I’m intending to use the Nginx page caching with a 60’ish second cache refresh time. With the refresh time that short, I won’t worry about the cache needing to refresh.

          It is possible to do cache purging with Nginx, but I haven’t figured it out yet and I haven’t had much luck getting the purge module working. Since I don’t badly need purging, I’m intending to just make do without any purging until I get around to figuring it out at a later date.

          • Take a look at https://wordpress.org/plugins/nginx-helper/ — It’s a plugin that manages purging the nginx cache at appropriate times for you. It works great.

            In addition to the nginx fastcgi cache for non-logged in users, I’m now experimenting with HHVM and redis-backed object caching. HHVM is fast enough that it is worth a little babysitting and implementing work-arounds for its once in a while instability. I run it with php-fpm as a failover.

            I had been using memcached with W3 total cache for object caching, but W3 total cache has caused me endless problems and it just seems to me like it is too big and trying to do too much. So I’m now switching over to redis and https://wordpress.org/plugins/redis-cache

    • There are two things I like about Batcache, one is that it is extremely easy to modify to suit your own needs. If you have something you need to customize, you can just hack up the built-in file to accomplish it. The inner workings of W3TC and WP Supercache are not so easy to understand.

      It also has a very moderate caching effect. By default (you can mess with the settings in the file), it only caches files for 300 seconds. So you end up with less issues with caches not being refreshed, since it’ll just automatically refresh itself after 300 seconds anyway.

      • In other words, batcache is the only plugin that has a good answer to the cache invalidation question. For the other plugins you need to erase the cache files which might be an expensive disk operation.

        Another very nice feature of batchache is that it tries (or tried? haven’t looked at its code for a while) to cache things only if there is an actual traffic surge to the specific post, and don’t waste your diskio for post that are being accessed only once in an hour. BTW I think that nginx can be configured to do the same but I don’t trust my own memory here.

        • Yep, you can set it to only cache pages accessed multiple times within a set period of time, I think pages need accessed more than twice during a 300 second period by default.

          Nginx can indeed also do that too. I’m assuming other systems like Varnish can do it too.

      • This depends on your server. If you use APC which means that all code is in memory and your file system is slow then it might be faster to serve cache out of memory even when paying the small penalty of initializing php.before sending the page from the batcache.
        If you want to be really smart with SC or W3TC you will store the cached file on a memory disk.

        • Both W3TC and WP Supercache can be configured to use APC, so I was comparing to that scenario. Since they more aggressively cache the pages, I think their out of the box setups running APC would be faster than Batcache (I haven’t checked though, that’s just a wild guess on my part). You could of course configure Batcache to cache everything for the next week, in which case it would be just as fast I guess.

          I didn’t even know you could serve pages from WP Supercache or W3TC from a memory disk. That is a really neat trick. I think I’ll stick with Nginx page caching for that myself though, since it’s presumably even faster.

  2. I have tried all of the solutions. And even on our high traffic WordPress site, it runs flawless using W3 total cache. We use enhanced disk caching for pages, and disk caching for objects/database.. W3 Total Cache has a bottleneck in the Minification that I posted at RTcamp, but Autoptimize will cover what you need. Just use the CSS + JS minification from the Basic Settings tab.

    Disk caching can really fly if you tune all aspects of the server for it.. By this I mean using RHEL Tuned or Ubuntu Tuned, This directly adds performance to the kernel / DBUS, You can run tuned in throughput-performance mode. You can boost page load times, using dns caching, we use http://members.home.nl/p.a.rombouts/pdnsd/index.html for this.

    This is just my preferred setup.. Sites like MaxCDN.com are running varnish, memcached and WordPress, and by looking at the source code, and their GTmetrix results, a lot of well known WordPress powered sites are struggling.. The same goes for Pagely, WPEngine and so on.. Newest technology isn’t always faster. These guys are so focused on Proprietary cache platforms, but thats not what makes WordPress fast.

    • I’m assuming you are referring here to complete page caching, not object caching. Disk based object caching is generally considered quite slow and inefficient.

      Complete page caching is quite a different although related subject. Even with static page caching running, you should still consider using an object cache, as some users will still need to experience fresh uncached pages, such as logged in users, commenters etc. That point, you need object caching to make any serious dent in page performance.

    • Sorry. I missed the bit where you said you used disk caching for objects. I find it interesting that it is working so well for you. I always though disk caching for small chunks of data would be significantly slower than grabbing it from a dedicated cache store.

  3. I tryed some ways to use cache in WordPress and nowadays my choice is W3 Total Cache because is quite simple to use and configure.

    I was using Varnish Cache for a long time and i was very happy with it, but since it not supports HTTPS i deleted it.

    On new versions of PHP (php 5.5) we can’t use APC, it was replaced with Zend Opcache (ex. Zend Optimizer+) and this optimizer not supports object cache.

    At the end of the day, install W3 Total Cache and use static page caching is best and simplest choice in my opinion.

    • There is no best choice for caching. That was in fact one of the main points of my post ;)

      I don’t think there are many situations in which using an object cache in conjunction with static page caching is a bad idea though. Most sites have situations in which caching chunks of data would be beneficial.

      Varnish’s lack of https support is definitely a problem. I’m not going to bother using it for that reason too.

      There is a new version of APC, called APCu, which can be used with newer versions of PHP.

  4. I did some tests on my server (i don’t have APC or similar installed), only W3 Total Cache plugin caching on disk (pages, objects and database).

    The weird part is the page generation time, plugin needs more time to generate a page when i have object cache enabled. If i disable object cache plugin need less time to generate the page.

    The plugin needs more time in page generation process, but perhaps is using less resources… i´m not sure. But i´m starting to have doubts about how beneficial is have object cache enabled on disk.

    • I’m not surprised the page generation time would take longer with object caching running, as it needs to spend time stashing the objects. If the object cache was primed beforehand, then you would probably notice the opposite effect.

      This would probably be particularly noticeable with disk caching, since caching to disk would typically take longer to store data in than a dedicated caching backend. The object cache benefits comes about when viewing pages which are not statically cached, eg: commenters, logged in users or anyone else who has triggered a cookie or needs to see unique content on the page. If you only serve static pages, then the object caching would not really help much, or may even slow things down as you noticed.

  5. *** On new versions of PHP (php 5.5) we can’t use APC, it was replaced with Zend Opcache (ex. Zend Optimizer+) and this optimizer not supports object cache. ***

    You can turn off zend opcache, either in php5/php.ini or php5/pool.d/www.conf

    If you are using W3 Total cache, you’d probably want to use the google xml sitemaps so that you can have W3 reload the cache automatically. This saves you from having to manually do it.

    The all Disk Cache method is a general configuration because 90% of the sites I optimize, don’t have access to Opcode caching, mostly shared hosts!

    But again, if you are running disk cache for everything, it’s better to understand the linux kernel / DBUS + sysctl.conf.. All the tutorials around the web are for making Nginx + WordPress go fast, but rarely do you even see servers, clouds, vps accounts truly configured for speed. There are a lot of areas to cover for fast disk caching, such as http://bjdean.id.au/wiki/LinuxMemoryManagement

    In the end, the combination you will want to choose, is the one that loads your pages the fastest, lessens the most http requests, descreases page size, and gives you the best scores on WebPageTest, GTMetrix ETC..

    • That turns off the opcode cache. Most people will want to leave that as is, but add an object cache backend on top, hence APCu would be suitable.

      I don’t know much about disk optimisation. Most experts I talk to seem to prefer to use Redis, APC or Memcached, so I tend to stick those.

Newsletter

Subscribe Via Email

Enter your email address to subscribe to this blog and receive notifications of new posts by email.