Memcache
Table of Contents
Memcache is an in-memory transient key/value store typically used for caching. It’s a key technology for building scalable web apps.
Local Memcache Setup
You will need to run a local memcached process to test against. Install it with Homebrew on Mac OS X:
$ brew install memcached
Or on Ubuntu:
$ sudo apt-get install memcached
Or follow these instructions for Windows.
You can also download the source from the memcached site.
Now run the memcached daemon:
$ memcached -vv
slab class 1: chunk size 88 perslab 11915
...
<15 server listening
Using Memcache from Ruby
If you are already using memcache, you won’t need to rewrite your code for it to run on Heroku. Only the gem dependency declaration and the memcache client object initialization (described below) need to change.
Gem Installation
If you’re using dalli but not Bundler, be sure to add it to your .gems manifest.
First remove any memcache client gems you may already be using from your application, such as memcache-client.
You must use a memcache gem that supports SASL. There are two available:
- Dalli (recommended): We recommend using dalli. Dalli supports Rails 2 & 3 and Ruby 1.8.7 & 1.9.2. It is compatible with all of our deployment stacks, and is the only gem you can use if you wish to use memcache for your sessions store in Rails 2 or 3. Full setup instructions for using dalli are available at the Dalli README. Please note that Dalli does not support older caching libraries such as cache-money or cache_fu.
Mac OS 10.5 Users A bug in port / Mac OS 10.5 causes an error when trying to build the memcached-northscale gem. Snow Leopard (10.6) users are unaffected. To resolve this, uninstall the cyrus-sasl2 library and then build the memcached-northscale gem. Once the memcached-northscale gem is built, you can reinstall the cyrus-sasl2 package if you require it.
- memcached-northscale is a Ruby interface to the libmemcached C client. Memcached-northscale should be used only if you require compatibility with old caching libraries like cache-money.
Add whichever gem you choose to your Gemfile and run bundle install.
Deploying to Heroku
To use memcache on Heroku, install the memcache add-on:
$ heroku addons:add memcache
If you’re using the memcached gem as described above, your app will use memcache on Heroku without any further code changes.
You will also have direct access to your memcache configuration via config vars:
$ heroku config
...
MEMCACHE_PASSWORD => xxxxxxxxxxxx
MEMCACHE_SERVERS => instance.hostname.net
MEMCACHE_USERNAME => xxxxxxxxxxxx
...
Rails Setup
Rails 2.3.3 and later abstracts caching mechanisms through Rails.cache. You must be using Rails 2.3.3 or newer to use memcache on Heroku.
Please see our documentation for a comprehensive look at Rails caching strategies on Heroku.
Dalli: Rails 3
In your Gemfile:
gem 'dalli'
In config/environments/production.rb:
config.cache_store = :dalli_store
Dalli: Rails 2.3.3 – 2.3.x
In config/environment.rb:
config.gem 'dalli'
In config/environments/production.rb:
# Object cache
require 'active_support/cache/dalli_store23'
config.cache_store = :dalli_store
In config/initializers/session_store.rb:
# Session cache
ActionController::Base.session = {
:namespace => 'sessions',
:expire_after => 20.minutes.to_i,
:memcache_server => ['server-1:11211', 'server-2:11211'],
:key => ...,
:secret => ...
}
require 'action_controller/session/dalli_store'
ActionController::Base.session_store = :dalli_store
Memcached-northscale: Rails 2.3.3 – 2.3.x
Add the gem via your Gemfile:
gem "memcached-northscale"
In config/environment.rb:
config.gem 'memcached-northscale', :lib => 'memcached'
require 'memcached'
In config/environment/production.rb:
config.cache_store = :mem_cache_store, Memcached::Rails.new
Development Environment
In your development environment, Rails.cache will default to an in-memory store that doesn’t require a running memcached.
Testing
You can test writing to the local memory cache in a console, or via heroku console:
$ script/console
>> Rails.cache.write('color', 'red')
And fetching the data back:
>> Rails.cache.read('color')
=> "red"
Using Memcache with Sinatra
With Dalli and Sinatra, it’s as easy as adding a :cache setting:
set :cache, Dalli::Client.new
get '/' do
settings.cache.set('color', 'blue')
settings.cache.get('color')
...
end
Getting Stats on Usage
Dalli gem gives you a handy stats method.
$ heroku console
Ruby console for myapp.heroku.com
>> Rails.cache.stats
=> {"mc3.ec2.northscale.net:11211"=>{"pid"=>"10414", "uptime"=>"59892", "time"=>"1301152323", "version"=>"1.4.4_188_g0117a2c", "pointer_size"=>"64", "rusage_user"=>"418.600000", "rusage_system"=>"545.170000", "daemon_connections"=>"10", "curr_connections"=>"1246", "total_connections"=>"666019", "connection_structures"=>"1271", "cmd_get"=>"5736", "cmd_set"=>"1028", "cmd_flush"=>"0", "auth_cmds"=>"3", "get_hits"=>"4852", "get_misses"=>"884", "delete_misses"=>"0", "delete_hits"=>"0", "incr_misses"=>"0", "incr_hits"=>"0", "decr_misses"=>"0", "decr_hits"=>"0", "cas_misses"=>"0", "cas_hits"=>"0", "cas_badval"=>"0", "bytes_read"=>"11886315", "bytes_written"=>"584
02597”, “limit_maxbytes”=>”67108864”, “rejected_conns”=>”0”, “threads”=>”4”, “conn_yields”=>”0”, “evictions”=>”0”, “curr_items”=>”81”, “total_items”=>”1028”, “bytes”=>”213275”, “engine_maxbytes”=>”104857600”}}
Further Reading
- Blazing Fast Speeds with Sinatra and Memcached by Erik Andrejko
Using Memcache from Java
Spymemcached is a popular Java Memcache client. In order to use Spymemcached in your project you have to declare the dependency in your build and initialize the client from the environment variables that Heroku provides to your application.
Sample code for the Java Memcache demo application is available on GitHub.
Add Spymemcached to your pom.xml
Add the following repository and dependency to your pom.xml in order to use Spymemcached to connect to Memcache:
<repository>
<id>spy</id>
<name>Spy Repository</name>
<layout>default</layout>
<url>http://files.couchbase.com/maven2/</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
...
<dependency>
<groupId>spy</groupId>
<artifactId>spymemcached</artifactId>
<version>2.7.3</version>
</dependency>
Use Spymemcached in your application
AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, new PlainCallbackHandler(System.getenv("MEMCACHE_USERNAME"), System.getenv("MEMCACHE_PASSWORD")));
ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
ConnectionFactory cf = factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(ad).build();
MemcachedClient memcachedClient = new MemcachedClient(cf, Collections.singletonList(new InetSocketAddress(System.getenv("MEMCACHE_SERVERS"), 11211)));
memcachedClient.add("test", 0, "testData");
Using Spymemcached with Spring
Use the following Java configuration class to set up a MemcachedClient object as a singleton Spring bean:
@Configuration
public class SpringConfig {
@Bean
public PlainCallbackHandler getPlainCallbackHandler() {
return new PlainCallbackHandler(System.getenv("MEMCACHE_USERNAME"), System.getenv("MEMCACHE_PASSWORD"));
}
@Bean
public AuthDescriptor getAuthDescriptor() {
return new AuthDescriptor(new String[]{"PLAIN"},
getPlainCallbackHandler());
}
@Bean
public ConnectionFactory getConnectionFactory() {
ConnectionFactoryBuilder factoryBuilder = new ConnectionFactoryBuilder();
return factoryBuilder.setProtocol(Protocol.BINARY).setAuthDescriptor(getAuthDescriptor()).build();
}
@Bean
public InetSocketAddress getServerAddress() {
return new InetSocketAddress(System.getenv("MEMCACHE_SERVERS"), 11211);
}
@Bean
public MemcachedClient getMemcachedClient() throws IOException{
MemcachedClient memcachedClient =
new MemcachedClient(
getConnectionFactory(),
Collections.singletonList(getServerAddress()));
return memcachedClient;
}
}
or the following XML configuration file:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<context:annotation-config/>
<context:property-placeholder/>
<bean id="plainCallbackHandler" class="net.spy.memcached.auth.PlainCallbackHandler">
<constructor-arg index="0" value="${MEMCACHE_USERNAME}"/>
<constructor-arg index="1" value="${MEMCACHE_PASSWORD}"/>
</bean>
<bean id="authDescriptor" class="net.spy.memcached.auth.AuthDescriptor">
<constructor-arg index="0">
<array><value>PLAIN</value></array>
</constructor-arg>
<constructor-arg index="1" ref="plainCallbackHandler"/>
</bean>
<bean id="memcachedClient" class="net.spy.memcached.spring.MemcachedClientFactoryBean">
<property name="servers" value="${MEMCACHE_SERVERS}:11211"/>
<property name="protocol" value="BINARY"/>
<property name="authDescriptor" ref="authDescriptor"/>
</bean>
</beans>
Sample code
To see a complete, working example, check out the sample code in github. The readme explains more about the example.
Using Memcache from Python
The memcache add-on requires SASL authentication. The de-facto Python memcache module, pylibmc, supports this protocol.
Module Installation
To connect to your local memcached instance, you can use the pylibmc module. You can install it easily with pip:
You will need libmemcached available to install the pylibmc module.
$ pip install pylibmc
Once pylibmc is installed, you can connect to memcache easily:
import pylibmc
# Connect to memcache.
mc = pylibmc.Client(servers=['127.0.0.1'])
Deploying to Heroku
To use memcache on Heroku, install the memcache add-on:
$ heroku addons:add memcache
Once the add-on is enabled, there will be a few environment variables available that contain the memcache connection details:
$ heroku config
MEMCACHE_PASSWORD => xxxxxxxxxxxx
MEMCACHE_SERVERS => instance.hostname.net
MEMCACHE_USERNAME => xxxxxxxxxxxx
...
Next, add pylibmc to your application’s requirements.txt file:
pylibmc==1.2.2
Sample Code
In your application, you can interface with the provided memcache server with only a few lines of code:
import os
import pylibmc
# Connect to memcache with config from environment variables.
mc = pylibmc.Client(
servers=[os.environ.get('MEMCACHE_SERVERS')],
username=os.environ.get('MEMCACHE_USERNAME'),
password=os.environ.get('MEMCACHE_PASSWORD'),
binary=True
)
Now, you have direct access to the memcache. See the pylibmc docs for more information.
Django Support
Unfortunately, Django’s built-in pylibmc caching support doesn’t support authentication yet. Luckily, there’s a SASL-compatible backend available.
To use it, add the following to your requirements.txt file:
pylibmc==1.2.2
django-pylibmc-sasl==0.2.4
Then, add it as the configured backend in your application settings:
CACHES = {
'default': {
'BACKEND': 'django_pylibmc.memcached.PyLibMCCache'
}
}
This will automatically configure Django to connect to the Memcached instance. No further configuration is required.