Heroku

How It Works

Memcache

Last Updated: 05 January 2012

caching dalli java memcache memcached python

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

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.

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.