Friday, July 11, 2008

User based memcached namespaces

So i ran into this interesting caching architecture problem where I needed a caching model such that each user had their own cache key, but one record update would invalidate every users' cache entries.  Since memcache does not support wildcards, and looping through cache keys is about as inefficient as it gets, after some memcached FAQ reading and some thought, I concluded the following cache model which is so simple, but is certainly very valuable.

Say you have a user who has many results, in a one to many relationship and can only see the results he/she has permission for.  This means every user can potentially have a different result set, hence a different cache value so 1 key per user.  We can very easily create a cache key called userid_results where userid is the unique ID of the user making the request.  Works well....until you add a new result.  If we have 1000 users, how do we invalidate all of those cache keys?  The following mechanism solves that issue:

  1. Create a version cache key named "results_version".  This cache key will simply hold the current version of the results table.  Whenever we insert a new record we increment the version.
  2. Create  a cache key that uses this version.  So in your code you will have to first fetch the version key (memcache->get(results_version)). Then use this value to generate the user cache key like user_results_results_version which would end up something like user_results_1003.  
  3. When a new record is inserted we increment the results_version key.  This sets it to 1004 in our example
  4. The next request for content will try to access user_results_1004, but this cache key does not exist yet so we will force a cache_miss, hit our DB or content source, then cache the result.



Unknown said...

Very ingenious! I was thinking about setting an overall timestamp of last revision, but I was missing the importance of adding it to the key!!!


StormByte said...

I have extended that idea to support multiple namespace binding to same data and to support immediatelly deletion of obsoleted keys.

You can check it in my blogger, maybe you find it useful too: