Cache miss stampedes

dormando dormando at
Thu Jul 26 08:30:44 UTC 2007

Well. Uh.

Sometimes ya just can't, yaknow? :)

In an ideal world your cache never expires, memcached never flaps, and 
you have tools updating caches in the background that work flawlessly. 
Unfortunately developers don't always have the time to make these 
perfect, but it's "easy" to patch in one of the previous suggestions to 
deal with the problem.

Lets say you're a typical startup and you're faced with a problem:

You have a complex bit of parsing code for special data. There was never 
any code written to automatically, or programmatically, update this 
data. Sometime in the future caching is added. This is easy; cache the 
result of the parsing request into memcached, let it expire once per 
minute so it's easy to propagate changes (which are made by hand, 
rarely). It's wrong, but it's what happened.

It might take someone a nontrivial amount of time to fix this. Write 
code to serialize the data into the DB, write a CLI tool or webpage to 
manage the data, so the cache can be updated after the data is edited 
(either by hand, or whatever). Good luck getting your boss to sign off 
on that. There're magic widgits that aren't writing themselves!

I do realize there's an easy way to update the data by hand, then run a 
tool to just refresh the cache, but that's besides the point ;) Imagine 
again that you have a lot of these situations. Where caching was plugged 
in as an afterthought. For new development I _always_ recommended a cron 
to update the data (getting PHP devs to write crons is like pulling 
teeth!), or a tool that updates the cache. It doesn't always happen.

At Gaia it's also common for this to happen where simple 'query caching' 
was plugged in as a caching methodology. Everywhere there's SQL that's 
relatively static, adding an ->enableCache(blah) call makes it faster! 
Right? Right... Turns out you can also plug in one of the aforementioned 
algorithms to mitigate this brain damage.

Also, if you have a cluster configured to not auto-rehash, and 
memcached's can stay down for multiple minutes during a failure, you 
will get a similar stampeding problem anyway. You should just cache the 
data in APC at this point anyway.

Well. In summary; you're right. On that note, I realize in all the wiki 
updatery I hadn't really stressed what you mentioned enough at all. It's 
there, but it's not a highlight.


Steven Grimm wrote:
> I admit I'm a bit baffled by this discussion (and I also admit I have 
> only been skimming it, so this might be a retread.) It seems like one of 
> two situations should be true:
> 1. The underlying data has not changed. The cache is therefore still 
> correct.
> 2. The underlying data has changed, and the cache is now stale.
> In the first case, just don't set an expiration time and you're done, 
> yes? Since the item is frequently hit (hence the stampedes) it will 
> never get LRUed out.
> In the second case, why are you waiting around for some unknown amount 
> of time to pass -- and for some client to get an actual cache miss -- 
> before refreshing the cache? If you have a few hot keys that change 
> often but for whatever reason you can't invalidate / update the cache at 
> the time the underlying data gets updated, then another approach is to 
> have some background task periodically updating the hot items to their 
> current values. Again, you don't let the item expire in this scenario; 
> it just gets updated every once in a while. This way nobody has to deal 
> with a cache miss, and the values still stay as current as you want them 
> to (adjust the frequency of your background task's updates to taste) 
> with no stampedes.
> What am I missing?
> -Steve

More information about the memcached mailing list