Object Caching in Rails
Mar 30th, 2007 by phil
Earlier this month Pat Eyler asked “What can Ruby on Rails learn from other web frameworks?”, and there have been surprisingly few responses. I think that most people find it difficult to criticize a tool that they really like. Or, it could be that Rails does so many things well that the average user doesn’t push the framework hard enough to expose its limitations. With everything that Rails gets right, it can be hard to spot the areas where it could use improvement. I have been working with Rails full time since January of 2006 and I still love it. I don’t think I could go back to J2EE development full time. But Rails isn’t perfect and there are a few things that other frameworks do better.
A common complaint is that ActiveRecord is very “chatty” with the database. In general it seems that the Object Relational Mapping (ORM) pattern often results in overly chatty applications. Developers use mapped objects as if they were local, when in fact the application state and any associations are stored in the database. This means that loading and saving the object and any related objects will result in round trips to the database. You can reduce this chattiness by being careful about how mapped objects are used, but that is not a complete solution. For one thing, it may force you into writing unnatural code to avoid round-trips to the database. Another problem is that using an ORM tool inherently limits your ability to fine tune queries and control when they are called.
A solution to this problem is aggressive caching. Hibernate is a mature Java ORM framework that is generally considered to be reasonably fast. Part of the reason for its good performance is its object caching features. There is a first-level cache that is used to cache objects during a transaction, a second-level cache that is “global” and caches objects across transactions, and a query cache that caches the results of HQL queries.
This level of caching can be difficult in Rails due to its “share nothing” philosophy. It is difficult to have an object live longer than a single request short of stashing the object into the session. Typically, multiple simultaneous requests to a Java application are handled by a pool of native threads that are all running in the same JVM process. Rails applications are serviced by separate operating system processes that do not share an address space.
An external object cache can be built using memcached. There are even two Rails plugins (CachedModel and acts_as_cached) that try to make this easy for ActiveRecord objects. Also, the Rails core team has recently added caching features to ActiveRecord (see here and here). These are both great efforts, and I think that object caching in Rails is generally moving in the right direction. I would still like to see a comprehensive caching strategy in ActiveRecord that covers all three areas as in Hibernate. Certainly, there is something to be learned from the experience the Hibernate developers have gained over the years.



We’ll likely be porting the Coherence API to Ruby. We’ve already build both pure Java and C# implementations, and are well on the way with C++, with a C wapper around the C++ API coming on its heels.
So what do you think, Coherence for Ruby? ;-)
Peace.
@Cameron: Wow. Yeah, that has the potential to be really cool. Especially if it has a very Rubyish API and tight integration with ActiveRecord.