转自:http://nubyonrails.com/articles/memcached-basics-for-rails
Many speedy sites use memcached to save the results of expensive database queries and intense rendered templates. This is a basic introduction to using memcached with Rails. Thanks to Eric Hodel and Layton Wedgeworth who have answered many questions.
Yes, there is a hash in the sky
Memcached is a lightweight server process that stakes out a fixed amount of memory and makes it available as a quick access object cache.
Some of the things you can do with it are:
- Automatically cache a row from the database as an ActiveRecord object
- Explicitly
render_to_string
and save the results (works well for tag clouds) - Manually store a complicated database query and retrieve it later
I thought there was some kind of fancy voodoo happening, but it turns out that it’s basically just a hash! You can put
a key and value into the cache, and get
it later. memcache-client also gives you a delete
method.
Objects are serialized using Marshal
, so it’s very fast.
@tags = Tag.find :all
Cache.put 'all_your_tags', @tags
Cache.put 'favorite_skateboarder', 'Tom Penny'
skateboarder = Cache.get 'favorite_skateboarder'
Cache.delete 'all_your_tags'
Installation on Mac OS X
I first installed the memcached server using DarwinPorts but each query was taking five seconds to answer. It turns out that this can be fixed. I wrote a shell script that builds memcached and dependencies with the proper fixes. Use at your own risk…
memcached Install Script for Mac OS X
Other platforms can find the source or an installer at the memcached site .
Install cached_model
The Robot Co-Op has made a few libraries available. cached_model
makes it easy to cache single row queries from ActiveRecord tables. memcache-client
is a pure Ruby client and is included with the installation of cached_model
.
sudo gem install cached_model
cached_model
requires Rails 1.1.2 or greater.
Start the memcached server
The memcached server takes several options but the defaults work well to start with. While learning, the -vv
argument shows what’s happening as values are entered and retrieved.
# Start the server with the default of 64 MB RAM
memcached -vv
Use with ActiveRecord
The easiest way to experiment with memcached is to make a new Rails app with a single database table. Add the following code to the bottom of config/environment.rb
:
require 'cached_model'
memcache_options = {
:c_threshold => 10_000,
:compression => true,
:debug => false,
:namespace => 'my_rails_app',
:readonly => false,
:urlencode => false
}
CACHE = MemCache.new memcache_options
CACHE.servers = 'localhost:11211'
NOTE : You should move this to config/environments/production.rb
for production.
You’re almost ready. Edit your model so it inherits from CachedModel
instead of ActiveRecord::Base
.
class Foo < CachedModel
end
Try it out
Finally, start ./script/console
and watch the output of memcached -vv
. It also helps to tail -f log/development.log
.
Create a few records, find
them by id, and watch as they are automatically placed in the cache. Finding the same record repeatedly should hit the cache, but not the database.
>> Foo.find 1
=> MemCache Get (0.134546) active_record:Foo:1
=> SELECT * FROM foos WHERE (foos.id = 1) LIMIT 1
=> MemCache Set (0.024758) active_record:Foo:1
>> Foo.find 1
=> MemCache Get (0.032337) active_record:Foo:1
If you save a record that is already in the cache, CachedModel
will automatically update it in the database and in the cache.
CachedModel
automatically creates unique keys based on the model name and id number. You can cache arbitrary data with the provided
Cache
object, but you will need to plan a consistent key system.
>> all_foo = Foo.find :all
>> Cache.put 'Foo:all', all_foo
=> MemCache Set (0.082277) Foo:all
>> Cache.get 'Foo:all'
=> [#<Foo:0x2642ad4 @attributes=...
A few things to remember
Cache.get
will returnnil
if the item is not in the cache. You can use this to determine whether something should be refetched and re-inserted into the cache.- Records in
CachedModel
expire after 15 minutes (or you can adjust the expiration time by settingCachedModel.ttl
). - Manually inserted objects can be expired, too.
Cache.put('foo', 'bar', 60)
will cause thefoo
key to expire in sixty seconds. - When the allotted memory fills up, older items will be deleted.
Deployment details
Production use of memcached deserves its own article. In the meantime…
- Memcached is only useful for a dedicated server or a VPS that has sufficient memory available.
- Try running an instance of memcached on each of your app servers. Running with 128 MB is sufficient for most applications.