RailsConf 2007: Chris Wanstrath: Kickin' Ass with Cache-fu

Posted by Nick Sieger Sat, 19 May 2007 20:34:00 GMT

Chris is here to talk about games, since he used to work for Gamespot. He coded PHP, which is like training wheels without the bike. He had to sit in a glass cube and help keep the site running during E3 last year. There were 100 gajillion teenage boys during their lunch break hitting refresh, and it all blew up. Couldn’t even gzip the responses, because the servers heated up to much. They served 50M pages in a day, without downtime. They did it with Memcache.

Memcache is a distributed hash -- multiple daemons running on different servers. Developed by Livejournal for their infrastructure, you just put up the servers, and they just work.

Should you use Memcache? No. YAGNI, UYRDNI (unless you really do need it).

Rails and Memcache

Fragments, Actions, Sessions, Objects, cache it all. You can use:

  • memcache-client (by Robot-coop guys/Eric Hodel). Marshal.unload is 40 times faster than Object.new/loading from the database.
  • CachedModel -- integration with ActiveRecord
  • Fragment Cache Store
  • Memcache session store

...or...

cache_fu

Or, acts_as_cached. It knows about all the aforementioned objects, with a single YAML config file (config/memcached.yml). Word to the wise: don’t use names in your server config file. Use IPs, avoid BIND and connections to the servers with every connection. Don’t let DNS outages bring down your servers.

  • get_cache
  • expire_cache

This is all you need -- if you’re using set_cache, you probably don’t understand how the plugin works. Expire cache on the “after save” hook, which allows you to cache ID misses as well.

class Presentation < ActiveRecord::Base
  acts_as_cached
  after_save :expire_cache
end

Example: only cache published items

class Presentation < ActiveRecord::Base
  acts_as_cached :conditions => 'published = 1'
end

Cached-scoped-finders (if somebody thinks of a good name, let Chris know). The idea is to move custom finder logic to a method on your model, and then wrap a cache-scoping thingy around it. cache_fu ties this up nicely by giving you a cached method on AR::Base.

class Topic < ActiveRecord::Base
  def self.weekly_popular
    Topic.find :all, ...
  end
end

Topic.cached(:weekly_popular)

Adding date to cache key with alias_method_chain:

def self.cache_key_with_date(id)
  ...
end

class << self
  alias_method_chain :cache_key, :date
end

Cached loads by ID: Topic.find(1, 2, 3) moves to Topic.get_cache(1, 2, 3), which can parallelize calls to memcached and bring them back as they’re ready.

user_ids = @topic.posts.map(&:user_id).uniq
@users = User.get_cache(user_ids)

You can also cache associations, so that you’re navigating associations via Memcache.

Cache overrides

class ApplicationController < ActionController::Base
  before_filter :set_cache_override
  def set_cache_override
    ActsAsCached.skip_cache_gets = !!params[:skip_cache]
  end
end

reset_cache: Slow, uncached operations can sometimes queue up and wedge a site. Instead, issue cache resets on completion of a request, rather than expiring beforehand. That way, requests that continue to pile up will still use the cached copy until the rebuild is complete.

class Presentation < ActiveRecord::Base
  after_save :reset_cache
end

Versioning: a way to expire cache on new code releases

class Presentation < ActiveRecord::Base
  acts_as_cached :version => 1
end

Deployment: Chris recommends using Monit to ensure your Memcache servers are up.

libketama: consistent hashing that gives you the ability to redeploy Memcache servers without invalidating all the keys.

Q: Page caching? A: Nginx with native Memcache page caching, but outside of Rails domains.

Lots of other questions, but dude, Chris talks too fast!

Tags ,  | 2 comments | no trackbacks

Comments

  1. Avatar Ravenii said about 9 hours later:

    Thanks Nick, I tried to trackback but I may have failed! here is a part I wrote; “Once I found that Nick was blogging, and found that I can catch up with presentations, that I have missed!, I gave up even thinking about writing. He did write a lot of very good material, I spent a lot of time reading his blog already!”

  2. Avatar Chris said 2 days later:

    Awesome notes! Great job, man.

Trackbacks

Use the following link to trackback from your own site:
http://blog.nicksieger.com/articles/trackback/247