Company Blog

Faster pages with memcached caching


Memcached caching is used by many sites to improve scalability. Facebook is reputed to have 3 terabytes of memcache storage distributed across 200 servers.

We recently added memcached based caching of Mergelab public feeds. This post is intended to share with other developers some of the existing Rails-based caching techniques and tools that we used.

Rails has decent caching capabilities built in, for example fragment caching, but there are functionality gaps in the standard toolkit. A number of libraries have been created to fill these gaps.

We used memcache-fragments to add time-based expiry of cached HTML fragments in the memcache. In our case, we wanted to cache the generated markup of the public feed news items, but only for up to 15 minutes. From the home page:

memcache_fragments is a very simple plugin (10 lines of code!) that

  1. makes rails fragment caching play nice with robot coop’s memcache-client by wrapping its get/set methods with read/write methods that rails expects.
  2. makes it easy to do time based fragment expiry using this syntax:
  <% cache 'my/cache/key', :expire => 10.minutes do %>
        ...
  <% end %>

This plugin relies upon memcached to do the actual work of time based expiry. (If you’re not using memcached, timed_fragment_cache will work with any cache system; I haven’t tried it yet.)

We used the techniques described in The Secret to Memcached to handle invalidation based on changes in session or object state.

Attempting to invalidate large numbers of dependent items each time something significant changes is slow and complex. Instead, the elegantly simple approach described in Tobias Luetke’s post uses very specific memcache keys to ensure that stale data is not fetched from the cache. For example, the keys used in a shopping application might include object version numbers and parameters that capture the state of a shopping cart:

At the beginning of each request we load a shop object which we pick depending on the incoming host name. We use the fact that we always load this shop model anyways and add versioning to it. This version column is incremented every time we want to sweep all caches.

Now we add the version number to the cache keys:

cache shop.version + params.values.sort.to_s  do
  ... load all data ...
end

this means that we will never get an outdated version from the caches because we ask them for a very specific thing. After the version number is increased in the database all incoming requests will miss the caches but will be re-cached quickly.

Memcached will automatically get rid of the stale keys once space is needed, least recently used keys are discarded first so there is no need for manual cleanup.

These same caching techniques are applicable to personal pages, where we will be applying them shortly to improve performance.





Comments



1
Author:  Faster pages with memcached caching » Bogle’s Blog | Date:  January 27, 2008 | Time:  10:54 pm

[…] Read more on the Mergelab blog […]



Write a Comment

Note: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>