IronCache

IronCache is an extension for ExpressionEngine 2 that implements whole-page caching using memcached, an extremely fast memory caching daemon. It was originally pontificated upon elsewhere, was inspired by the BatCache plugin for WordPress and has been in use at Grist for about 18 months now. It is designed to massively reduce the stress on high-traffic sites running EE, and decrease page load times. We wrote IronCache because it was useful to us — we hope the same for you.
Update: IronCache is now MSM compatible. Thanks to Lee Hilton for his testing on this.
How does IronCache work?
Features of IronCache
What do I need in order to use IronCache?
Warnings
Who supports IronCache?
Downloading and installing IronCache
Configuring your cache
Shout Outs
IronCache works by providing a shortcut to EE. Under conditions that you specify, EE will save a complete copy of its output to memcached using a URI-unique key. Then, early in each front-end page request , IronCache causes EE to quickly check the cache for that particular page’s key. If found, it outputs the HTML for the page and exits, rather than going through the rest of its rather long and expensive song and dance. This saves a great deal of PHP work and reduces the number of database queries required to load a page to a bare minimum.
- It is highly configurable. Caching hit/miss is by URI pattern (regex). The extension will cache only those URIs of your site that you want it to, and will cache each part with the sensitivity and duration that you specify. For example, you could set a 5 minute cache on your homepage with very high sensitivity, while caching your internal pages for 10 minutes at a relatively low sensitivity.
- It is login aware. For logged-in sessions, it’s as if IronCache did not even exist — EE does everything normally.
- It provides a header hint. Want to know if your page came from IronCache, or if IronCache is working? Check the headers!
What do I need in order to use IronCache?
- You will need to know how to write simple regular expressions. Part of configuring Ironcache involves telling it what URLs to cache, and you will use regex to do that. Mistakes here can lead to rather large problems with your cache.
- You will need a running memcached daemon, You should also know how to support and interact with memcached.
- You will need to be running ExpressionEngine 2.2, since this is the only environment we’ve tested IronCache on. It may work on earlier versions of EE2, but we’re not sure. There’s no public EE 1.x version.
- More generally: please only use this extension if you know what you are doing — misconfiguration could bring down your site.
- IronCache fails gracefully if your memcached instance suddenly goes away, but it should not be run in the absence of a working, configured memcached server because it can make your site marginally slower.
- Part of the magic of IronCache is that it extends EE’s native Output class. If you are running other add-ons that also do this (run the command `grep -rl ‘extends EE_Output’` on your extensions and/or thrid_party folders to tell for sure) IronCache and/or the other extension may not work, though there are sometimes work-arounds for this.
Glad you asked because this is important. NO ONE! We’re releasing this software into the wild because it’s been useful for us, but we can’t guarantee that it will work in any particular situation. We’ve cleaned it up and standardized it as best we can, and will respond to questions and bug reports as we are able, but please know that you’re using this software at your own risk. Have an improvement? Write it up and let us know on github and we’ll fold it in.
Downloading and installing IronCache
(we strongly suggest doing this in a test environment, rather than a live site.)
1. Download the extension.
2. Unpack the folder as required and move the folder called ironcache into the third_party directory of your EE2 instance. (make sure the permissions on everything in the folder are correct and that it is executable by the user running apache etc.)
3. From EE control panel, install the extension, which should now be on the extension list.
4. Open the settings screen for IronCache, and configure your cache (see below.)
5. That’s it you’re done!

enabled: turns the cache on and off
memcached host: the host for your memcached instance
memcached port: the port for memcached (default: 11211)
prefix: a string that will append to all of your keys. This allows EE to share the same cache with various other applications or environments
caching configuration: a strictly formatted string that controls how IronCache works. Each line of the configuration looks like this:
pattern||cache_time||counter_reset||threshold
pattern: a regular expression that will match against your URIs. Leave this empty to write a rule caching the homepage.
cache_time: once cached, pages of this type will stay in cache for this long, in seconds
counter_reset: the sensitivity counter will reset in this many seconds
threshold: if the page is viewed this many times in counter_reset seconds, it gets cached
This can be summarized in the following sentence: if a page with URI matching pattern is generated threshold times in counter_reset seconds, it is placed in the cache for cache_time seconds.
Examples:
^article||300||10||2
A rule that will cache any page whose URL begins with the string “article” for five minutes if it is viewed twice in ten seconds.
^cars|^trucks|^motorbikes||600||1||1
A rule that will cache any page whose URL begins with any of the strings “cars” “trucks” or “motorbikes” for ten minutes if it is viewed even once.
||1200||10||3
A rule that will cache the homepage for twenty minutes if it is viewed three times in ten seconds.
IronCache was made by Darcy Christ (@1000camels), Nathan Letsinger (@natebot) and Matt Perry (@mattoperry) at Grist.
This software was inspired by BatCache for WordPress, and was written in the day or so following a conversation with Matt Mullenweg.
Special thanks to Brian Litzinger for his early and very helpful comment.

[...] information, downloads, documentation, etc. is here! Share this:TwitterFacebookStumbleUponDiggEmailLike this:LikeBe the first to like this [...]
Please try IronCache — a memcached extension for ExpressionEngine « Grist Labs
September 19, 2011 at 11:49 pm
Looks very nice. Word of note, Custom System Messages extends the EE_Output class. I have not tested IronCache with CSM though. Matt, I can provide you a copy of CSM if you want to test it with IronCache.
litzinger
September 21, 2011 at 8:41 am
Hey Thanks Brian! It’d be great — if you send me a copy I’ll test it out. mperry[at]grist.org … by the way, I just tweeted you a link to this page, so please ignore! Thanks again for your suggestion long ago.
Matt
September 21, 2011 at 9:09 am
varnish caching, standard expire headers on content would have made more logical sense for caching full pages. memcached would have been more useful for caching db caching, tag caching, etc. on pages of logged in members or sections of a site you would not want cache fronted like say forums. memcached usage seems like reinventing an already proven wheel in varnish, with added complexity. Also why only support a single memcached server if you were going to use this for caching a busy site. Using two or more memcached servers would have allowed maintenance or death of a single memcached instance without affecting site performance. But here again multiple varnish servers using proper expire headers would have been more useful.
Brian James
September 21, 2011 at 9:06 am
Hey Brian,
Thanks for your comments. Varnish and other reverse proxies are great! We use them at Grist alongside this extension. I think that every situation is a bit different, however, and this just provides an additional caching tool that was rather obviously missing from ExpressionEngine (but not from Drupal or WordPress.) In fact, it’s interesting to note that wordpress.com (with tens of millions of blogs) does not use any reverse proxies, but relies only on memcache for whole page caching. IronCache is a port of that simple-but-important WordPress plugin (called BatCache … there’s also one called SuperCache … do you detect a theme?)
Regarding multiple memcached servers: that’s a good idea. Maybe I’ll build failover into the next version of this. Then you could use it, for example, with a memcached cluster. In our experience, memcached is extremely stable and almost never goes down. If it does (and we’ve tested our stuff with the cache turned off) the latency introduced by IronCache is in reality very minimal.
Matt
September 21, 2011 at 9:23 am
hey Brian,
One more little comment — ironCache does not cache if you are logged in … just noticed you mentioned that.
Matt
September 21, 2011 at 9:39 am
The logged in issue is one we’ve run into a lot dealing with caching, whether it’s built in EE caching or external, and it was my first thought when I started reading your description here. It’s a shame that there’s not a good way to use this type of caching when logged in/logged out state matters, which is a fairly common condition. In particular it applies to my use case, devot-ee.com, where all of our pages have a logged in/logged out state due to our header.
The other thing that would be really cool is a more common-user friendly CP, with the ability to add and remove URI rules without getting into full-on regex. I understand you’re just releasing an internal tool here, but with some polishing an add-on like this could be a very useful commercial add-on.
On another note, I’ve spoken on EE optimization (caching included) at one conference last year and will be speaking on it again at the ExpressionEngine and CodeIgniter Conference in New York this fall, and your work (and past presentations) have been invaluable to me in building content and ideas for those talks, so thanks for that!
Jacob Russell (@jacobrussell)
September 27, 2011 at 1:12 pm
@jacob — Hey thanks for the kind words and thanks for checking out ironCache.
Yah I would love to clean up the UI on this and make it easier to add rules. I think I’ll do that next when I get the time — should be just a matter of tweaking the backend interface which is mercifully easier in EE2 than in EE1.
Regarding logged-in/logged-out state — it’s an interesting problem. Logged-in pages are very difficult to cache in general (at least in a whole-page way) because in general there’s something unique about them to the logged-in user. Therefore they can’t really be re-used for other users, and so even if you did cache them … you get the idea. Also, on media sites in particular (like Grist) 99% of the traffic, especially during spikes, is not from logged-in users. So we get a huge amount of benefit from caching that portion of the traffic and not worrying so much about the logged-in people.
If you have a web app or site where much of the load is generated by logged-in people, then you have to find ways to cache parts of the page — those parts that are the same no matter what the state. That’s a bit of a different problem, and it’s actually not handled too badly by EE’s template caching or also the snippets add-on from Solspace (though I haven’t checked on that in a while.)
Anyway good luck with this — I’ll try to get around to updating the ironCache interface before long … it’s a bit clunky!
Matt
September 29, 2011 at 12:03 am
I’m working with an MSM install. This is causing some 500 errors on 2nd, 3rd and N-th site. I’ve disabled it for now, but is IronCache currently MSM compatible?
Lee Hilton
October 3, 2011 at 5:02 pm
Hey Lee — Thanks for the report. I haven’t tested it on MSM, so no sorry I can’t guarantee it will work. I can’t think of any reason why it shouldn’t though, but I’d need to test. If you send me an email at mperry [A+] grist [d0t] org … perhaps we can get it tested an working on MSM.
Matt
October 3, 2011 at 11:23 pm
Update: IronCache now works on MSM
Matt
October 11, 2011 at 2:49 pm
This is good stuff… No offense, but this should be a commercial product, and based upon the level of page hits for clients needing ‘full page cache’ it would be an easy sell. We’re coming from a Magento full page cache experience and we’ve finally found something similar. I’ll check back in after we implement this in a production environment.
Nate
November 25, 2011 at 6:14 pm
Excellent Nate — glad you found IronCache. Let me know if you run into any snags as you implement it.
Matt
November 26, 2011 at 1:01 am
How does clearing the cache work? If updates are made in the EE control panel, do the caches have to expire naturally, or are they reset upon content updates? Thanks!
Matt
December 2, 2011 at 9:52 am
Hi Matt — good question. Currently there’s no cache flush when you update an entry. This is a pretty cool idea though. Keys in IronCache are based on the URI of the cached page, so in the case of (for example) an article, you could expire the cache for that URI on update.
What I’d have to think more about is how easy it actually is to determine the URI of a piece of content at the time you update it. Since ExpressionEngine is MVC, the template and template group and therefore the URI (unless set as a property of the channel) is not directly associated with the content (or at least I can’t think of how it is right now.) But like I say I’d have to think about that more — any ideas?
Of course the content might show up in some way in more than one place (like an index page or the home page) so you really wouldn’t be able to rotate the caches on all of these pages.
In lots of cases for high-traffic sites, it’s highly effective to set the cache time for IronCache as low as 30 seconds or a minute .. this would mean that you’d need to wait at most that amount of time for the cache to rotate.
Matt
December 2, 2011 at 10:44 am
Thanks, that all makes sense. Seems like it won’t be an issue if the refresh times are low.
So, I got things working locally (I can see the IronCache header in the response). In production however, I am not seeing the IronCache headers. The Memcached -vv output looks like it is doing something though. I get the following in the Memcahced -vv output from ONE request. Does it look normal?
new auto-negotiating client connection
Client using the ascii protocol
incr test__1_929c742e335dc537819703b2031d5823_c 1
2
get test__1_929c742e335dc537819703b2031d5823_p
END
get test__1_929c742e335dc537819703b2031d5823_c
sending key test__1_929c742e335dc537819703b2031d5823_c
END
set test__1_929c742e335dc537819703b2031d5823_f 0 30 4
STORED
connection closed.
new auto-negotiating client connection
Client using the ascii protocol
get test__1_929c742e335dc537819703b2031d5823_f
sending key test__1_929c742e335dc537819703b2031d5823_f
END
set test__1_929c742e335dc537819703b2031d5823_p 0 500 0
STORED
connection closed.
The number on the fourth line increments with each request. It will reset randomly though… and looks like this when it does:
new auto-negotiating client connection
Client using the ascii protocol
incr test__1_929c742e335dc537819703b2031d5823_c 1
NOT_FOUND
set test__1_929c742e335dc537819703b2031d5823_c 0 30 1
STORED
get test__1_929c742e335dc537819703b2031d5823_p
sending key test__1_929c742e335dc537819703b2031d5823_p
END
get test__1_929c742e335dc537819703b2031d5823_c
sending key test__1_929c742e335dc537819703b2031d5823_c
END
connection closed.
I get the resetting thing locally too. Does that all look like it should?
Thanks!
Matt
December 7, 2011 at 3:47 pm
[...] Jan 2012: Here’s an idea: ignore everything below and visit the IronCache page on GristLabs. There, you can download IronCache rather than just reading about [...]
IronCache: Caching Expression Engine with memcached [UPDATED] « StkyWll
January 15, 2012 at 1:19 am