5 ms·
Everyone should be using low level caching in Rails
- Jake232 14y agoNice fist post. For anyone interested, he's another awesome guide to Rails Caching. Worth a read too. - http://broadcastingadam.com/2011/05/advanced_caching_in_rails http://broadcastingadam.com/2011/05/advanced_caching_in_rail...
- jaylevitt 14y agoThere used to be many model-caching plugins for Rails, but few if any made the transition to Rails 3. The record-cache gem looks interesting and flexible, though I haven't tried it: https://github.com/orslumen/record-cache https://github.com/orslumen/record-cache
- robotmay 14y agoI recall trying out cache-money a while back. I haven't tried out any of the current equivalents, but I may have to give them a go just to see what they can do.
- ruckusing 14y agocache-money is probably the most full-featured and battle-tested (coming from Twitter and now taken over by ngmoco). However its biggest drawback is that its hard-wired to use memcached. It would be great if the actual cache backend was pluggable and we could develop a redis adapter. As it stands the memcached integration is pretty deeply intertwined into the cache-money library.
- rapind 14y agoIdentityMap is going to greatly reduce the need for model caching for the majority of sites. High traffic sites with a lot of data will still benefit from a distributed cache though. http://api.rubyonrails.org/classes/ActiveRecord/IdentityMap.html http://api.rubyonrails.org/classes/ActiveRecord/IdentityMap....
- jaylevitt 14y agoThat would be wonderful. Unfortunately, IdentityMap was disabled by default in 3.1 because it was incomplete, and it was pulled from 4.0 for a while due to lack of development: https://github.com/rails/rails/pull/5261 https://github.com/rails/rails/pull/5261 Though there is now a company volunteering to fund completion of the feature, starting Real Soon Now: https://github.com/rails/rails/issues/5442 https://github.com/rails/rails/issues/5442 IdentityMap would, obviously, be great. Though I didn't realize it could serve as a replacement for model caching; didn't IdentityMap, like the query cache, only last for the lifetime of a request? Or could it be persisted in the Rails.cache of your choice for an arbitrary lifespan?
- rapind 14y agoIdentityMap stores the model in memory for the process. Only storing for the lifetime of a request wouldn't be terribly useful. IdentityMap will be extremely useful for the majority of sites since they have very low traffic, processor, and memory demands, and therefore it's unlikely you'll have too many processes running using up their own memory containers. Though you could argue these sites really don't need additional caching anyways (they'd still respond slightly faster with IdentityMap). For high traffic sites it'll still be useful to save some trips, but you'll also want to implement and manage a distributed cache (for models, actions, fragments, etc). It's available and sort of works now. You just have to turn it on and be mindful of how associations are handled. Still a work in progress.
- FabPelletier 14y agoInteresting tips, I'll be sure to try them out.
- wavesplash 14y agoExcellent. You may wish to mention that the default Rails.cache is a per-process cache and doesn't work between instances / goes away at process death. For Memcache users, configure Rails.cache to use Rails' built in :memcache_store: http://api.rubyonrails.org/classes/ActiveSupport/Cache/MemCacheStore.html http://api.rubyonrails.org/classes/ActiveSupport/Cache/MemCa... For Redis fans, try :redis_store: https://github.com/jodosha/redis-store https://github.com/jodosha/redis-store This covers Rails 3 caching pretty well: http://broadcastingadam.com/2011/05/advanced_caching_in_rails http://broadcastingadam.com/2011/05/advanced_caching_in_rail... Note for Rails 2: If I recall correctly, in Rails 2 fragment caching/action caching still uses the filesystem even if you have a cache_store set.
- robotmay 14y agoAye, I was going on the assumption that people were using memcached/redis. I'll add a little section in case anyone wasn't sure about that bit :)
- pselbert 14y agoAs a small addendum, I strongly recommend dalli (https://github.com/mperham/dalli https://github.com/mperham/dalli) over the default memcached library. It is written by the former maintainer of the memcached gem, is smaller in size, up to 20% faster, and most importantly to me, is actively maintained. Most of that info is in the readme, btw.
- rapind 14y agoIf by everyone he means anyone who's reached a point in their application where it's worth adding code and complexity in order to improve performance, then yes this is useful (and I use it often). http://c2.com/cgi/wiki?PrematureOptimization http://c2.com/cgi/wiki?PrematureOptimization
- bnorton 14y agoThis is good information, but could you explain why you think that everyone should use caching? You don't mention testing in this article so is it safe to say that you don't? Do you have performance tests that show that the caching actualy matters for you application workload?
- robotmay 14y agoI do test for caching (though I must admit I write first, test later); I'll write that up in a later post. Similarly, I'll put up some comparisons to show the performance difference those changes have made :) I think everyone should be caching as the speed of your page loads is fast becoming an even more important factor in people using/enjoying your site. Everyone (including myself) is getting more impatient in regards to page load speed, and every little helps. Also, you never know when you'll hit the frontpage on HN!
- getsat 14y agoGood article. A few things: Use "if" and "present?" instead of "unless" and "blank?". It's much easier to parse mentally, especially for people who didn't write the code. :) You don't need to use "self" to access latitude, longitude, updated_at, etc. You only need to use it for assignment. You don't need to call #to_s on the captured exception. When you interpolate an object into a string, Ruby calls #to_s on the supplied object itself, e.g., "I am an #{Object}". I'd probably also add a "has_posts" scope to Category and use that instead of the #where call in ApplicationController.
- robotmay 14y agoThanks for the feedback! I'll keep that in mind for the future; it's a bad habit of mine :D I actually didn't realise you only needed that for assignment. That's going to neaten up my code somewhat. I normally don't put .to_s in strings like that, so I'm not entirely sure why I did in that line. Aye, I'd normally use a scope but I figured I'd write it out more verbosely just for clarity :)