Cache miss stampedes
dormando at rydia.net
Thu Jul 26 08:30:44 UTC 2007
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
> 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?
More information about the memcached