This week I, with help from many, got [WordPressMU][wordpress] setup to use [memcached][memcached].
The instructions for doing all this are on the Internet, but I thought it might help others (or at least my future self) to compile them all in one spot.
### How WordPress caches
There are two layers of caching in WordPress:
* An object level cache, similar to Django’s [low-level cache][django-cache]
* Page level caching, provided by plugins, similar to Django’s [per-view cache][django-page-cache]
By the time we’re done, we’ll have both using memcache. The object cache defaults to the file system, and most folks use [WP Super Cache][super-cache] which caches pages to the filesystem as well.
### Object caching
* Install the [PHP memcache module][php-memcache]
* Add these settings to your **wp-config.php**
global $memcached_servers; $memcached_servers = array('default' => array('127.0.0.1:11211'));
You can add as many servers and change the port number to match your memcached setup. Example:
global $memcached_servers; $memcached_servers = array('default' => array('bradfitzrocks:11211', 'bradfitzrocks2.mycompanydomain.com:90210'));
* Install the memcache version of WordPress’s [object-cache.php][wp-object-cache] to your blog’s wp-content folder.
I don’t want to sidetrack myself comparing how much [Django][django] rocks compared to PHP or WordPress, but I will anyway! In Django, your cache setup is a [setting][cache-setting], which makes local development soooo much easier.
Stop here and you’ll be live with WordPress object caching.
### Page caching
* You must have followed the steps above to hook up WordPress’s object cache to memcache.
* If it’s installed, uninstall [WP Super Cache][super-cache]
* Install [Batcache][batcache-github] by putting advanced-cache.php file in your blog’s wp-content folder, and batcache.php in your blog’s wp-content/plugins folder.
* Activate the Batcache plugin from within the admin interface, if you’re on WordPressMU use the “Activate X Site Wide” link.
* Hit reload on a page a few times and then view source and you should see something like this:
<!-- generated 12 seconds ago generated in 0.683 seconds served from batcache in 0.006 seconds expires in 288 seconds --> </head>
* Optionally, tweak Batcache’s behavior by editing the options in advanced-cache.php
var $max_age = 300; // Expire batcache items aged this many seconds (zero to disable batcache) var $remote = 0; // Zero disables sending buffers to remote datacenters (req/sec is never sent) var $times = 2; // Only batcache a page after it is accessed this many times... (two or more) var $seconds = 120; // ...in this many seconds (zero to ignore this and use batcache immediately) var $group = 'batcache'; // Name of memcached group. You can simulate a cache flush by changing this. var $unique = array(); // If you conditionally serve different content, put the variable values here. var $headers = array(); // Add headers here. These will be sent with every response from the cache. var $uncached_headers = array('transfer-encoding'); // These headers will never be cached. Apply strtolower. var $debug = true; // Set false to hide the batcache info <!-- comment --> var $cache_control = true; // Set false to disable Last-Modified and Cache-Control headers var $cancel = false; // Change this to cancel the output buffer. Use batcache_cancel();
The Batcache version I linked to is a GitHub fork of [Andy Skelton’s](http://github.com/skeltoac/batcache) original version. My fork includes a patch to make sure the Content-Type header is set correctly on non-HTML pages. I’m hoping to add some more cache invalidation rules on top of the great work Andy already did.
Many thanks to the following folks:
* [Mohanjith](http://mohanjith.net/blog/2008/10/using-memcached-with-wordpress-object-cache.html) for the object cache set up
* [Andy Skelton](http://skeltoac.com/) for creating Batcache and being kind enough to drop a version on GitHub for me to fork
* [Casey Bisson](http://maisonbisson.com/blog/post/13773/fixing-batcache-to-send-the-correct-content-type-header/) for describing the content-type patch for Batcache
One issue that we ran into recently had to do with hash values across multiple memcached servers. We noticed that one of the cached objects wasn’t updating memcached. We found that the hashes for that object were different on each of our memcached servers. This probably happened when one of the servers became unresponsive and temporarily dropped out of the pool. The default setting for PECL_MEMCACHED uses a “standard” hashing algorithm which works fine for single-server implementations. But when using multiple memcached servers, you’re better off switching to a consistent hashing algorithm which will retain the object’s hash key across multiple servers.
Thanks for your tutorial, t’s the most complete I’ve found yet with all the steps to install memcache on wpmu (might be missing a bit of info on memcache install, but I’m sure people can figure it out).
I cant succeed in getting the stats in my source code, I suppose the system is not working on my side, did you have a similar problem during your install? do you know a place where I can put a flag to debug the problem?
Thanks a lot 🙂
Finally, I’ve found the root of the problem, batcache doesn’t serve pages for connected users 🙂
Glad you figured that out! Batcache, and I believe Super Cache both serve non-cached pages to logged in users.
Thanks for posting this.
I have an issue with this it seems to work for a bit (I see the cached info before the head) then it just stops the memcache server is still alive so that is not the issue. I also see SEGFAULT errors as soon as I disable the segfaults disappear?
How can you add memcached layer for aws opsworks for wordpress?