Sunday, August 31, 2008

Memcache in Reusable Code

If you're writing code for Google App Engine, they highly recommend using Memcache. Here's the deal: when they're measuring what they're going to charge you for, they include CPU and bandwidth. Memory is free. Using memcache to avoid database accesses is a very easy way to increase the number of pages you can serve within your quota. This is especially true if you have complex queries that need to be done for every requested page. Of course, outside of App Engine, memcache is useful for the same reason that Google recommends it.

Memcache has a very simple API. It takes a single key for each cached object. In an application which uses memcache in different places, this means that you must make sure that keys are globally unique. In my App Engine application, I've created a module that I'm planning to release, so that others can use it in their applications (more on that later). But how do I ensure that my keys are unique and won't collide with any application that it gets used in?

The solution: I adopted a very simple key naming convention throughout my application, which I also used in the module. I searched and could find no standard key naming convention for memcache, so I hereby propose this convention as a standard.

All memcache keys consist of a prefix followed by a context-specific unique value. The prefix depends on what's being cached, as follows:

CaseFormatUnique value
Model instanceModel.field=uniqueField value
Class instanceClassName.attribute=uniqueAttribute value
Class dataClassName.meaning:uniqueMeaning-specific value

Notice the use of = for instances and : for class data. Why is this needed? Well, suppose inside a class you decide to cache some data that isn't the instance of the class, such as something that takes a long time to calculate. Now, suppose somebody else decides to cache instances of your class. You might have a key conflict. By only permitting the : prefixes within a class definition, such name conflicts are avoided.

If you're caching an instance of a model or a non-model class, use =. If you're caching something else within a class, use :.

If what you're caching has a single, obvious key, then you can omit the ".field" portion of the key without problems (for example, Model=key). In practice, I think most uses can use this short form, but I'm defining the longer forms now to avoid confusion where they are needed.

I also added this to the App Engine Cookbook.


Post a Comment