Skip Navigation
Show nav
Heroku Dev Center
  • Get Started
  • Documentation
  • Changelog
  • Search
  • Get Started
    • Node.js
    • Ruby on Rails
    • Ruby
    • Python
    • Java
    • PHP
    • Go
    • Scala
    • Clojure
  • Documentation
  • Changelog
  • More
    Additional Resources
    • Home
    • Elements
    • Products
    • Pricing
    • Careers
    • Help
    • Status
    • Events
    • Podcasts
    • Compliance Center
    Heroku Blog

    Heroku Blog

    Find out what's new with Heroku on our blog.

    Visit Blog
  • Log inorSign up
View categories

Categories

  • Heroku Architecture
    • Dynos (app containers)
    • Stacks (operating system images)
    • Networking & DNS
    • Platform Policies
    • Platform Principles
  • Command Line
  • Deployment
    • Deploying with Git
    • Deploying with Docker
    • Deployment Integrations
  • Continuous Delivery
    • Continuous Integration
  • Language Support
    • Node.js
    • Ruby
      • Working with Bundler
      • Rails Support
    • Python
      • Working with Django
      • Background Jobs in Python
    • Java
      • Working with Maven
      • Java Database Operations
      • Working with the Play Framework
      • Working with Spring Boot
      • Java Advanced Topics
    • PHP
    • Go
      • Go Dependency Management
    • Scala
    • Clojure
  • Databases & Data Management
    • Heroku Postgres
      • Postgres Basics
      • Postgres Performance
      • Postgres Data Transfer & Preservation
      • Postgres Availability
      • Postgres Special Topics
    • Heroku Redis
    • Apache Kafka on Heroku
    • Other Data Stores
  • Monitoring & Metrics
    • Logging
  • App Performance
  • Add-ons
    • All Add-ons
  • Collaboration
  • Security
    • App Security
    • Identities & Authentication
    • Compliance
  • Heroku Enterprise
    • Private Spaces
      • Infrastructure Networking
    • Enterprise Accounts
    • Enterprise Teams
    • Heroku Connect (Salesforce sync)
    • Single Sign-on (SSO)
  • Patterns & Best Practices
  • Extending Heroku
    • Platform API
    • App Webhooks
    • Heroku Labs
    • Building Add-ons
      • Add-on Development Tasks
      • Add-on APIs
      • Add-on Guidelines & Requirements
    • Building CLI Plugins
    • Developing Buildpacks
    • Dev Center
  • Accounts & Billing
  • Troubleshooting & Support
  • Add-ons
  • All Add-ons
  • MemCachier
MemCachier

This add-on is operated by MemCachier

Reliable and powerful memcache-as-a-service

MemCachier

Last updated April 13, 2020

Table of Contents

  • Getting started
  • Supported Protocols: ASCII & Binary
  • Ruby
  • Rails
  • Ruby Puma Webserver
  • Rails Rack::Cache
  • Python
  • Django
  • Flask
  • PHP
  • Laravel
  • Symfony2
  • CakePHP
  • WordPress
  • Node.js
  • Java
  • Spring Boot
  • Go
  • Gin
  • Rust
  • Client library support
  • Sample applications
  • Local usage
  • MemCachier analytics
  • Analytics API
  • New Relic integration
  • Credentials
  • Disabled Caches
  • Encrypted Connections (TLS)
  • Upgrading and downgrading
  • Using MemCachier
  • Key-Value size limit (1MB)
  • Errors about app trying to connect to localhost
  • Support

MemCachier is an implementation of the Memcache in-memory key/value store used for caching data. It is a key technology in modern web applications for scaling and reducing server loads. The MemCachier add-on manages and scales clusters of memcache servers so you can focus on your app. Tell us how much memory you need and get started for free instantly. Add capacity later as you need it.

Follow our blog or twitter (@memcachier), for status and product announcements.

Getting started

Start by installing the add-on:

$ heroku addons:create memcachier:dev

You can start with more memory if you know you’ll need it:

$ heroku addons:create memcachier:100
$ heroku addons:create memcachier:500
 ... etc ...

Once the add-on has been added you’ll notice three new variables in heroku config:

$ heroku config
...
MEMCACHIER_SERVERS    => mcX.ec2.memcachier.com
MEMCACHIER_USERNAME   => bobslob
MEMCACHIER_PASSWORD   => l0nGr4ndoMstr1Ngo5strang3CHaR4cteRS
...

Next, setup your app to start using the cache. We have documentation for the following languages and frameworks:

  • Ruby
  • Rails
  • Ruby Puma Webserver
  • Rack::Cache
  • Python
  • Django
  • PHP
  • WordPress
  • CakePHP
  • Symfony2
  • Laravel
  • Node.js
  • Java

Your credentials may take up to three (3) minutes to be synced to our servers. You may see authentication errors if you start using the cache immediately.

Supported Protocols: ASCII & Binary

MemCachier supports both the memcache binary and ASCII protocols. Our preferred method is to use the binary protocol as it natively supports user authentication and improves the performance slightly over the ASCII protocol. All our documentation is written for using the binary protocol.

The ASCII protocol does not natively support user authentication. For MemCachier, where all connections require authentication, we extend the ASCII protocol in a very simple way. Once the connection is established, you should send a set command with your username as the key and your password as the value. For example:

$ telnet 35865.1e4cfd.us-east-3.ec2.prod.memcachier.com 11211
>
> set 15F38e 0 0 32
> 52353F9F1C4017CC16FD348B982ED47D
> STORED

You’ll need to do this quickly! As we timeout connections that don’t authenticate within a few seconds. Once authenticated, the full ASCII protocol is available to you.

Ruby

We’ve built a small Ruby Sinatra example. Source code or Deploy.

Start by adding the dalli gem to your Gemfile. Dalli is a Ruby memcache client.

gem 'dalli'

Then run bundle install:

$ bundle install

You can now start writing some code. First, you’ll need to create a client object with the correct credentials and settings:

require 'dalli'
cache = Dalli::Client.new((ENV["MEMCACHIER_SERVERS"] || "").split(","),
                    {:username => ENV["MEMCACHIER_USERNAME"],
                     :password => ENV["MEMCACHIER_PASSWORD"],
                     :failover => true,            # default is true
                     :socket_timeout => 1.5,       # default is 0.5
                     :socket_failure_delay => 0.2, # default is 0.01
                     :down_retry_delay => 60       # default is 60
                    })

Now you can use the cache through simple get and set operations, as well as many others.

cache.set("foo", "bar")
puts cache.get("foo")

Testing (Ruby)

The easiest way to test that your setup is working is through the heroku console:

$ heroku run console --app <app>
>> require 'dalli'
>> cache = Dalli::Client.new(ENV["MEMCACHIER_SERVERS"].split(","),
                        {:username => ENV["MEMCACHIER_USERNAME"],
                         :password => ENV["MEMCACHIER_PASSWORD"]
                        })
>> cache.set('memcachier', 'rocks')
=> true

And then fetch the value back:

>> cache.get('memcachier')
=> "rocks"

You can also get an insight into your cache usage (number of keys stored and bytes) with the stats command:

>> cache.stats
=> {"memcachier.example.net:11211" => {"cur_items" => "49982", "bytes" => "89982234"} }

Rails

We’ve built a small Rails example. Source code or Deploy.

We also have a tutorial on using MemCachier with Rails here.

Here we explain how you setup and install MemCachier with Rails. Refer to the Rails caching guide for information on how you use MemCachier with Rails. Rails supports automatic whole site caching, per-view caching and fragment caching.

Start by adding the dalli gem to your Gemfile. Dalli is a Ruby memcache client.

gem 'dalli'

Then run bundle install:

$ bundle install

Once this gem is installed you’ll want to configure the Rails cache_store appropriately. Modify your config/environments/production.rb with the following:

config.cache_store = :mem_cache_store,
                    (ENV["MEMCACHIER_SERVERS"] || "").split(","),
                    {:username => ENV["MEMCACHIER_USERNAME"],
                     :password => ENV["MEMCACHIER_PASSWORD"],
                     :failover => true,
                     :socket_timeout => 1.5,
                     :socket_failure_delay => 0.2,
                     :down_retry_delay => 60
                    }

In your development environment, Rails.cache defaults to a simple in-memory store and so it doesn’t require a running memcached.

From here you can use the following code examples to use the cache in your Rails app:

Rails.cache.write("foo", "bar")
puts Rails.cache.read("foo")

It is possible you will run into a configuration problem if you are using Rails 3.1 and the Heroku Cedar platform. Information on how to fix that issue can be found at this Stackoverflow answer

Testing (Rails)

To test locally you can simply use the rails console:

rails console
>> Rails.cache.write('memcachier', 'rocks')
=> true
>> Rails.cache.read('memcachier')
=> "rocks"

To test against MemCachier itself, refer to the Ruby testing instructions.

Rails 2

When adding the dalli gem to your Rails 2 Gemfile you will need to use dalli v1.0.5 as later versions of Dalli don’t support Rails 2.

gem 'dalli', '~>1.0.5'

Also modify config/environment.rb to contain:

config.gem 'dalli'

Else proceed just as newer Rails versions.

Ruby Puma Webserver

If you are using the Puma webserver for your Ruby app (Rails or otherwise), then you should take some additional steps due to the multi-threaded runtime being used. This applies to all threaded webservers for Ruby, not just Puma.

First, please refer to the documentation on Rails or Ruby appropriately, and then take these additional steps.

Dalli by default uses a single connection to each server. This works fine normally, but can become a bottleneck in a multi-threaded environment and limit performance. In this case, Dalli supports connection pooling, where multiple connections are created to MemCachier’s servers. To use this, start by adding the connection_pool gem to your Gemfile:

gem 'connection_pool'

Next, you’ll need to set the :pool_size configuration option when setting up Dalli. For example, in Rails your configuration would become:

config.cache_store = :mem_cache_store,
                    (ENV["MEMCACHIER_SERVERS"] || "").split(","),
                    {:username => ENV["MEMCACHIER_USERNAME"],
                     :password => ENV["MEMCACHIER_PASSWORD"],
                     :failover => true,
                     :socket_timeout => 1.5,
                     :socket_failure_delay => 0.2,
                     :down_retry_delay => 60,
                     :pool_size => 5
                    }

Where the number 5 should be chosen according to how many threads you will be running and the available concurrency on the machines running your webserver.

Rails Rack::Cache

Rails can use a middle-ware component of the Rack web server architecture called Rack::Cache. This provides caching of static assets in Rails and is a simple alternative to use a full CDN.

Please see this article for information.

Python

Here we explain how you setup and install MemCachier with Python.

We recommend the python-binary-memcached memcache client as it is a pure Python library. However, if you prefer, you can use pylibmc which has a larger ecosystem.

Recommended client: python-binary-memcached

This is a pure python client that supports the binary protocol and SASL authentication.

To install python-binary-memcached:

$ pip install python-binary-memcached

Be sure to update your requirements.txt file with these new requirements (note that your versions may differ than what’s below):

python-binary-memcached==0.28.0

Next, configure your memcached client in the following way:

import bmemcached
import os

servers = os.environ.get('MEMCACHIER_SERVERS', '').split(',')
user = os.environ.get('MEMCACHIER_USERNAME', '')
passw = os.environ.get('MEMCACHIER_PASSWORD', '')

mc = bmemcached.Client(servers, username=user, password=passw)

mc.enable_retry_delay(True)  # Enabled by default. Sets retry delay to 5s.

After this, you can start writing cache code in your Python app:

mc.set("foo", "bar")
print(mc.get("foo"))

Alternative client: pylibmc

This client relies on the C libmemcached library. This should be fairly straight-forward to install with your package manager on Linux or Windows. We also have a blog post for Ubuntu users on how to do this. You only need to be concerned about this for local development, the Heroku platform includes libmemcached.

Once it’s installed, then install pylibmc:

$ pip install pylibmc

Be sure to update your requirements.txt file with these new requirements (note that your versions may differ than what’s below):

pylibmc==1.5.2

The above pylibmc requirements must be added directly to your requirements.txt file. They shouldn’t be placed in an included pip requirement file. The Heroku Python buildpack checks the requirements.txt file and only that file for the presence of pylibmc to trigger bootstrapping libmemcached, which is prerequisite for installing pylibmc.

Next, configure your memcached client in the following way:

import pylibmc
import os

servers = os.environ.get('MEMCACHIER_SERVERS', '').split(',')
user = os.environ.get('MEMCACHIER_USERNAME', '')
passw = os.environ.get('MEMCACHIER_PASSWORD', '')

mc = pylibmc.Client(servers, binary=True,
                    username=user, password=passw,
                    behaviors={
                      # Faster IO
                      'tcp_nodelay': True,

                      # Keep connection alive
                      'tcp_keepalive': True,

                      # Timeout for set/get requests
                      'connect_timeout': 2000, # ms
                      'send_timeout': 750 * 1000, # us
                      'receive_timeout': 750 * 1000, # us
                      '_poll_timeout': 2000, # ms

                      # Better failover
                      'ketama': True,
                      'remove_failed': 1,
                      'retry_timeout': 2,
                      'dead_timeout': 30,
                    })

After this, you can start writing cache code in your Python app:

mc.set("foo", "bar")
print(mc.get("foo"))

A confusing error message you may get from pylibmc is MemcachedError: error 37 from memcached_set: SYSTEM ERROR (Resource temporarily unavailable). This indicates that you are trying to store a value larger than 1MB. MemCachier has a hard limit of 1MB for the size of key-value pairs. To work around this, either consider sharding the data or using a different technology. The benefit of an in-memory key-value store diminishes at 1MB and higher.

Django

We’ve built a small Django example. Source code or Deploy.
We also have a tutorial on using Django and MemCachier together here.

 

We recommend the django-bmemcached Django backend, as it uses the python-binary-memcached memcache client which is a pure Python library. However, if you prefer, you can try the pylibmc memcache client which has a larger ecosystem. However, it can sometimes be difficult to install locally as it relies on the C libmemcached library.

Here we explain how you setup and install MemCachier with Django. Please see the Django caching guide for how you effectively use MemCachier. Django supports whole site caching, per-view caching and fragement caching.

Recommended client: python-binary-memcached

MemCachier has been tested with the python-binary-memcached memcache client. This is a great client, fully-featured, high-performance and Python 2 & 3 support. Older Django versions require django-pylibmc to work with MemCachier. Please follow the instructions in this example if you wish to use an older version.

Install django-bmemcached:

$ pip install django-bmemcached

Be sure to update your requirements.txt file with these new requirements (note that your versions may differ than what’s below):

django-bmemcached==0.2.4

Note: The above django-bmemcached requirements must be added directly to your requirements.txt file. They shouldn’t be placed in an included pip requirement file.

Next, configure your settings.py file the following way:

servers = os.environ['MEMCACHIER_SERVERS']
username = os.environ['MEMCACHIER_USERNAME']
password = os.environ['MEMCACHIER_PASSWORD']

CACHES = {
    'default': {
        # Use django-bmemcached
        'BACKEND': 'django_bmemcached.memcached.BMemcached',

        # TIMEOUT is not the connection timeout! It's the default expiration
        # timeout that should be applied to keys! Setting it to `None`
        # disables expiration.
        'TIMEOUT': None,

        'LOCATION': servers,

        'OPTIONS': {
            'username': username,
            'password': password,
        }
    }
}

After this, you can start writing cache code in your Django app:

from django.core.cache import cache
cache.set("foo", "bar")
print cache.get("foo")

Alternative client: pylibmc

MemCachier has been tested with the pylibmc memcache client. This is a great client, fully-featured, high-performance and Python 2 & 3 support. As of Version 1.11 Django has out-of-the-box support for pylibmc. Older Django versions require django-pylibmc to work with MemCachier. Please follow the instructions in this example if you wish to use an older version.

The pylibmc client relies on the C libmemcached library. This should be fairly straight-forward to install with your package manager on Linux or Windows. For Mac OSX users, homebrew provides and easy solution. We also have a blog post for Ubuntu users on how to do this. You only need to be concerned about this for local development, the Heroku platform includes libmemcached.

Once libmemcached is installed, then install pylibmc:

$ pip install pylibmc

Be sure to update your requirements.txt file with these new requirements (note that your versions may differ than what’s below):

pylibmc==1.5.1

Note: The above pylibmc requirements must be added directly to your requirements.txt file. They shouldn’t be placed in an included pip requirement file. The Heroku Python buildpack checks the requirements.txt file and only that file for the presence of pylibmc to trigger bootstrapping libmemcached, which is prerequisite for installing pylibmc.

Next, configure your settings.py file the following way:

servers = os.environ['MEMCACHIER_SERVERS']
username = os.environ['MEMCACHIER_USERNAME']
password = os.environ['MEMCACHIER_PASSWORD']

CACHES = {
    'default': {
        # Use pylibmc
        'BACKEND': 'django.core.cache.backends.memcached.PyLibMCCache',

        # TIMEOUT is not the connection timeout! It's the default expiration
        # timeout that should be applied to keys! Setting it to `None`
        # disables expiration.
        'TIMEOUT': None,

        'LOCATION': servers,

        'OPTIONS': {
            # Use binary memcache protocol (needed for authentication)
            'binary': True,
            'username': username,
            'password': password,
            'behaviors': {
                # Enable faster IO
                'no_block': True,
                'tcp_nodelay': True,

                # Keep connection alive
                'tcp_keepalive': True,

                # Timeout settings
                'connect_timeout': 2000, # ms
                'send_timeout': 750 * 1000, # us
                'receive_timeout': 750 * 1000, # us
                '_poll_timeout': 2000, # ms

                # Better failover
                'ketama': True,
                'remove_failed': 1,
                'retry_timeout': 2,
                'dead_timeout': 30,
            }
        }
    }
}

After this, you can start writing cache code in your Django app:

from django.core.cache import cache
cache.set("foo", "bar")
print cache.get("foo")

A confusing error message you may get from pylibmc is MemcachedError: error 37 from memcached_set: SYSTEM ERROR (Resource temporarily unavailable). This indicates that you are trying to store a value larger than 1MB. MemCachier has a hard limit of 1MB for the size of key-value pairs. To work around this, either consider sharding the data or using a different technology. The benefit of an in-memory key-value store diminishes at 1MB and higher.

Template fragment caching

Django allows you to cache rendered template fragments. To enable fragment caching, add {% load cache %} to the top of each template caching is used in. The control statement to cache a fragment has the form {% cache timeout key ... %} where all additional parameters after the key are just appended to the key. In practice this may look as follows:

{% load cache %}
<!-- ... -->

<!-- Fragment caching example -->
{% for item in list %}
  {% cache None 'item-fragment' item.id %}
  <div>
    <!-- fragment that does something with the item -->
  </div>
  {% endcache %}
{% endfor %}

Here the timeout is None, but it can also be a variable that contains a time or an integer denoting seconds.

The cached snippet from the above example can be invalidated (deleted) as follows:

from django.core.cache import cache
from django.core.cache.utils import make_template_fragment_key
key = make_template_fragment_key("item-fragment", vary_on=[str(item.id)])
cache.delete(key)

View caching

Django also provides a decorator to cache views:

from django.shortcuts import render_to_response
from django.views.decorators.cache import cache_page
# ...

timeout = 600 # 10 min

@cache_page(timeout)
def index(request):
  # ...
  return render_template('index.html', ...)

If a cached view ever has to be invalidated explicitly, the key to the view needs to be saved:

from django.shortcuts import render_to_response
from django.views.decorators.cache import cache_page
from django.utils.cache import learn_cache_key
# ...

timeout = None
view_keys = {}

@cache_page(timeout)
def index(request):
  # ...
  response = render_template('index.html', ...)
  view_keys['index'] = learn_cache_key(request, response)
  return response

Now the view can be invalidated with:

from django.core.cache import cache
cache.delete(view_keys['index'])

Session storage

Memcache works well for storing information for short-lived sessions that time out. However, because Memcache is a cache and therefore not persistent, long-lived sessions are better suited to permanent storage options, such as your database.

For short-lived sessions configure SESSION_ENGINE to use the cache backend in django_tasklist/settings.py:

SESSION_ENGINE = 'django.contrib.sessions.backends.cache'

For long-lived sessions Django allows you to use a write-through cache, backed by a database. This is the best option for performance while guaranteeing persistence. To use the write-through cache, configure the SESSION_ENGINE in django_tasklist/settings.py like so:

SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'

For more information on how to use sessions in Django, please see the Django Session Documentation

Flask

We’ve built a small Flask example. Source code or Deploy.
We also have a tutorial on using Flask and MemCachier together here.

Here we explain how you setup and install MemCachier with Flask. While Flask has a built-in caching backend its features are limited to manual caching. For this reason we recommend you use the Flask-Caching package. Flask-Caching supports memoization, fragment caching (Jinja2 snippets), and whole view caching. For more details about how to use Flask-Caching please refer to its documentation

Flask-Caching requires the pylibmc client which relies on the C libmemcached library. This should be fairly straight-forward to install with your package manager on Linux or Windows. For Mac OSX users, homebrew provides and easy solution. We also have a blog post for Ubuntu users on how to do this. You only need to be concerned about this for local development, the Heroku platform includes libmemcached.

Once libmemcached is installed, then install Flask-Caching and pylibmc:

$ pip install Flask-Caching pylibmc

Be sure to update your requirements.txt file with these new requirements (note that your versions may differ than what’s below):

Flask-Caching==1.4.0
pylibmc==1.5.2

Note: The above pylibmc requirements must be added directly to your requirements.txt file. They shouldn’t be placed in an included pip requirement file. The Heroku Python buildpack checks the requirements.txt file and only that file for the presence of pylibmc to trigger bootstrapping libmemcached, which is prerequisite for installing pylibmc.

Next, configure your Flask app the following way:

import os
from flask import Flask
from flask_caching import Cache

cache = Cache()
app = Flask(__name__)

cache_servers = os.environ.get('MEMCACHIER_SERVERS')
if cache_servers == None:
    # Fall back to simple in memory cache (development)
    cache.init_app(app, config={'CACHE_TYPE': 'simple'})
else:
    cache_user = os.environ.get('MEMCACHIER_USERNAME') or ''
    cache_pass = os.environ.get('MEMCACHIER_PASSWORD') or ''
    cache.init_app(app,
        config={'CACHE_TYPE': 'saslmemcached',
                'CACHE_MEMCACHED_SERVERS': cache_servers.split(','),
                'CACHE_MEMCACHED_USERNAME': cache_user,
                'CACHE_MEMCACHED_PASSWORD': cache_pass,
                'CACHE_OPTIONS': { 'behaviors': {
                    # Faster IO
                    'tcp_nodelay': True,
                    # Keep connection alive
                    'tcp_keepalive': True,
                    # Timeout for set/get requests
                    'connect_timeout': 2000, # ms
                    'send_timeout': 750 * 1000, # us
                    'receive_timeout': 750 * 1000, # us
                    '_poll_timeout': 2000, # ms
                    # Better failover
                    'ketama': True,
                    'remove_failed': 1,
                    'retry_timeout': 2,
                    'dead_timeout': 30}}})

After this, you can start writing cache code in your Flask app:

cache.set("foo", "bar")
print cache.get("foo")

Function memoization

Flask-Caching provides a decorator to memoize functions. This basically means when the function is called, Flask-Cache will check if the result is in the cache and if it is not it will run the function and save the result to the cache. The memoize decorator works as follows:

@cache.memoize()
def run_expensive_computation(parameter):
    # ...
    return result

If you need to invalidate stale data you can either delete all memoized results for a function with cache.delete_memoized(run_expensive_computation) or a result for a specific parameter with cache.delete_memoized(run_expensive_computation, parameter).

View caching

Flask-Caching also provides a decorator to cache views:

@bp.route('/', methods=('GET',))
@cache.cached()
def index():
  # ...
  return render_template('index.html', ...)

It is important to note that the @cache.cached() decorator is directly above the definiton of the index() function, i.e., below the @bp.route() decorator.

The views are cached with a key of the form 'view/' + request.path. This is important to know if you ever need to invalidate a cached view. You can do that with cache.delete('view/'+path_of_stale_view)

Jinja2 snippet caching

Flask-Caching provides a Jinja2 control flow statement to cache snippets. The statement has the form {% cache timeout, key, ... %} where all additional parameters after the key are just appended to the key. In practice this may look as follows:

<!-- Snippet caching example -->
{% for item in list %}
  {% cache None, 'item', item['id']|string %}
  <div>
    <!-- Jinja2 snippet that does something with the item -->
  </div>
  {% endcache %}
{% endfor %}

Here the timeout is None but it can also be a variable that contains a time or an integer denoting seconds.

The cached snippet from the above example can be invalidated (deleted) as follows:

from flask_caching import make_template_fragment_key
key = make_template_fragment_key('item', vary_on=[str(item.id)])
cache.delete(key)

Session caching

Memcache works well for storing information for short-lived sessions that time out. However, because Memcache is a cache and therefore not persistent, long-lived sessions are better suited to permanent storage options, such as your database.

To store sessions in Memcache, you need Flask-Session.

$ pip install Flask-Session pylibmc

Be sure to update your requirements.txt file with these new requirements (note that your versions may differ than what’s below):

Flask-Session==0.3.1
pylibmc==1.5.2

Now, configure Flask-Session:

import os
import pylibmc
from flask import Flask
from flask_session import Session

app = Flask(__name__)

servers = os.environ.get('MEMCACHIER_SERVERS').split(',')
username = os.environ.get('MEMCACHIER_USERNAME')
passwd = os.environ.get('MEMCACHIER_PASSWORD')

app.config.from_mapping(
    SESSION_TYPE = 'memcached',
    SESSION_MEMCACHED =
        pylibmc.Client(cache_servers.split(','), binary=True,
                       username=cache_user, password=cache_pass,
                       behaviors={
                            # Faster IO
                            'tcp_nodelay': True,
                            # Keep connection alive
                            'tcp_keepalive': True,
                            # Timeout for set/get requests
                            'connect_timeout': 2000, # ms
                            'send_timeout': 750 * 1000, # us
                            'receive_timeout': 750 * 1000, # us
                            '_poll_timeout': 2000, # ms
                            # Better failover
                            'ketama': True,
                            'remove_failed': 1,
                            'retry_timeout': 2,
                            'dead_timeout': 30,
                       })
)
Session(app)

You can now use sessions in your app like so:

from flask import session
session['key'] = 'value'
session.get('key', 'not set')

PHP

We’ve built a small PHP example. Source code or Deploy.

 

Heroku recently improved their PHP support, please see their documentation if you aren’t familiar with the new model.

PHP Memcached Client

We recommended you use the PHP Memcached client to connect with MemCachier. It supports the full protocol and has great performance.

The php-memcached client is not a pure PHP client but a PECL extension that makes use of libmemcached. You thus need to install php-memcached via your OS package manager. In older operating systems you have to make sure libmemcached has SASL authentication support enabled but for newer operating systems such as Ubuntu 16.04 this is the default. After the installation you need to uncomment ;extension=memcached.so in /etc/php/conf.d/memcached.ini for the extension to work. On Heroku this dependency is already installed and configured.

First, you’ll need to modify your composer.json file to include the module:

{
    "require": {
        "php": ">=5.3.2",
        "ext-memcached": "*"
    }
}

Next, ensure that your new requirements are “frozen” to composer.lock by running:

$ composer update

For more information on enabling the extension and potential troubleshooting (e.g. when you don’t have the memcached extension available on your local computer), refer to the using optional extensions extensions section of Heroku’s PHP reference documentation.

Then, you can connect to MemCachier using the client:

require 'vendor/autoload.php';

// create a new persistent client
$m = new Memcached("memcached_pool");
$m->setOption(Memcached::OPT_BINARY_PROTOCOL, TRUE);

// some nicer default options
// - nicer TCP options
$m->setOption(Memcached::OPT_TCP_NODELAY, TRUE);
$m->setOption(Memcached::OPT_NO_BLOCK, FALSE);
// - timeouts
$m->setOption(Memcached::OPT_CONNECT_TIMEOUT, 2000);    // ms
$m->setOption(Memcached::OPT_POLL_TIMEOUT, 2000);       // ms
$m->setOption(Memcached::OPT_RECV_TIMEOUT, 750 * 1000); // us
$m->setOption(Memcached::OPT_SEND_TIMEOUT, 750 * 1000); // us
// - better failover
$m->setOption(Memcached::OPT_DISTRIBUTION, Memcached::DISTRIBUTION_CONSISTENT);
$m->setOption(Memcached::OPT_LIBKETAMA_COMPATIBLE, TRUE);
$m->setOption(Memcached::OPT_RETRY_TIMEOUT, 2);
$m->setOption(Memcached::OPT_SERVER_FAILURE_LIMIT, 1);
$m->setOption(Memcached::OPT_AUTO_EJECT_HOSTS, TRUE);

// setup authentication
$m->setSaslAuthData( getenv("MEMCACHIER_USERNAME")
                   , getenv("MEMCACHIER_PASSWORD") );

// We use a consistent connection to memcached, so only add in the
// servers first time through otherwise we end up duplicating our
// connections to the server.
if (!$m->getServerList()) {
    // parse server config
    $servers = explode(",", getenv("MEMCACHIER_SERVERS"));
    foreach ($servers as $s) {
        $parts = explode(":", $s);
        $m->addServer($parts[0], $parts[1]);
    }
}

You should look at the PHP Memcached client documentation for a list of API calls you can make against MemCachier.

PHP Session Support

You can configure PHP to store sessions in MemCachier as follows.

First, start by configuring an appropriate .user.ini in your document root (see heroku ini guide). It should contain the following:

session.save_handler=memcached
memcached.sess_sasl_username=${MEMCACHIER_USERNAME}
memcached.sess_sasl_password=${MEMCACHIER_PASSWORD}

; PHP 7
memcached.sess_binary_protocol=1
session.save_path="${MEMCACHIER_SERVERS}"
memcached.sess_persistent=On

; PHP 5 (uncomment the following and replace PHP 7 section above)
;memcached.sess_binary=1
;session.save_path="PERSISTENT=myapp_session ${MEMCACHIER_SERVERS}"

In your code you should then be able to run:

// Enable MemCachier session support
session_start();
$_SESSION['test'] = 42;

Alternative PHP Client – MemcacheSASL

This is not our recommended client for using MemCachier from PHP. We recommend the php memcached client. However, it may work better for you if you are running into any problems with the php memcached client.

You should first install the PHPMemcacheSASL client. You can either grab the code directly or use composer for package management. We suggest composer.

First, if using composer, you’ll need to modify your composer.json file to include the module:

{
    "require": {
        "php": ">=5.3.2",
        "memcachier/php-memcache-sasl": ">=1.0.1"
    }
}

Then, you can connect to MemCachier using the client:

require 'vendor/autoload.php';
use MemCachier\MemcacheSASL;

// Create client
$m = new MemcacheSASL();
$servers = explode(",", getenv("MEMCACHIER_SERVERS"));
foreach ($servers as $s) {
    $parts = explode(":", $s);
    $m->addServer($parts[0], $parts[1]);
}

// Setup authentication
$m->setSaslAuthData( getenv("MEMCACHIER_USERNAME")
                   , getenv("MEMCACHIER_PASSWORD") );

// Test client
$m->add("foo", "bar");
echo $m->get("foo");

Laravel

We’ve built a small Laravel example. Source code or Deploy.
We also have a tutorial on using Laravel with MemCachier here.

As of Laravel 5.3, memcached is supported out of the box with the php-memcached PECL extension. Instructions on how to install php-memcached can be found here. Older versions of Laravel require laravel-memcached-plus for memcached integration.

Before setting up memcached as your default cache we need to add the dependency to composer.json:

$ composer require ext-memcached

Then we need to config the cache in config/cache.php:

'memcached' => [
    'driver' => 'memcached',
    'persistent_id' => 'memcached_pool_id',
    'sasl' => [
        env('MEMCACHIER_USERNAME'),
        env('MEMCACHIER_PASSWORD'),
    ],
    'options' => [
        // some nicer default options
        // - nicer TCP options
        Memcached::OPT_TCP_NODELAY => TRUE,
        Memcached::OPT_NO_BLOCK => FALSE,
        // - timeouts
        Memcached::OPT_CONNECT_TIMEOUT => 2000,    // ms
        Memcached::OPT_POLL_TIMEOUT => 2000,       // ms
        Memcached::OPT_RECV_TIMEOUT => 750 * 1000, // us
        Memcached::OPT_SEND_TIMEOUT => 750 * 1000, // us
        // - better failover
        Memcached::OPT_DISTRIBUTION => Memcached::DISTRIBUTION_CONSISTENT,
        Memcached::OPT_LIBKETAMA_COMPATIBLE => TRUE,
        Memcached::OPT_RETRY_TIMEOUT => 2,
        Memcached::OPT_SERVER_FAILURE_LIMIT => 1,
        Memcached::OPT_AUTO_EJECT_HOSTS => TRUE,

    ],
    'servers' => array_map(function($s) {
        $parts = explode(":", $s);
        return [
            'host' => $parts[0],
            'port' => $parts[1],
            'weight' => 100,
        ];
      }, explode(",", env('MEMCACHIER_SERVERS', 'localhost:11211')))
],

For Laravel to use memcached as its cache you will need to set the CACHE_DRIVER environment variable:

$ heroku config:set CACHE_DRIVER=memcached

Note, if you prefer you may also configure memcached to be your default cache driver in config/cache.php:

'default' => env('CACHE_DRIVER', 'memcached'),

For more information on how to use the cache in Laravel, we recommend you consult the Laravel caching documentation or our Laravel tutorial.

Use memcached for session storage

Memcached works well for sessions that time out, however, since memcached is a cache and thus not persistent, saving long-lived sessions in memcached might not be ideal. For long-lived sessions consider a permanent storage option such as you database.

Changing the session store from a file (default) to memcached can be done easily by just setting an environment variable:

$ heroku config:set SESSION_DRIVER=memcached

Caching rendered partials

With the help of laravel-partialcache you can also cache rendered partials in Laravel. This is essentially the same as fragment caching in Ruby on Rails. If you have complex partials in your application it is a good idea to cache them because rendering HTML can be a CPU intensive task.

Do not cache partials that include forms with CSRF tokens.

You can add this dependency to your Laravel project with

$ composer require spatie/laravel-partialcache

and it will give you the @cache blade directive. It works just like the @include directive with a few added parameters.

For example,

@cache('my-complex.partial', ['data' => $data], null, $data->id)

will include my-complex.partial, pass it $data with the identifier data and cache it forever (null) and add $data->id to the cache key.

You can invalidate this cached partial with from your code with PartialCache::forget('my-complex.partial', $data->id);.

Caching entire reponses

In Laravel it is also easy to cache the entire rendered HTML response by using laravel-responsecache. This is essentially the same as view caching in Ruby on Rails. This package is easy to use and has good documentation in it’s README. To use this package with memcached you have to set the environment variable RESPONSE_CACHE_DRIVER to memcached.

Symfony2

The Symfony2 framework is a great choice with Heroku and MemCachier. It supports caching and storing sessions in Memcache.

First, start by configuring an appropriate .user.ini in your document root (see heroku ini guide). It should contain the following:

session.save_handler=memcached
memcached.sess_binary=1
session.save_path="PERSISTENT=myapp_session ${MEMCACHIER_SERVERS}"
memcached.sess_sasl_username=${MEMCACHIER_USERNAME}
memcached.sess_sasl_password=${MEMCACHIER_PASSWORD}

CakePHP

The CakePHP framework has excellent support for caching and can be easily used with MemCachier as the provider. To setup CakePHP with MemCachier, you’ll need to edit the file app/Config/bootstrap.php and add the following lines:

Cache::config('default', array(
    'engine' => 'Memcached',
    'prefix' => 'mc_',
    'duration' => '+7 days',
    'compress' => false,
    'persistent' => 'memcachier',
    'servers' => explode(',', getenv('MEMCACHIER_SERVERS')),
    'login' => getenv('MEMCACHIER_USERNAME'),
    'password' => getenv('MEMCACHIER_PASSWORD'),
    'serialize' => 'php'
));

After that, you should be able to use caching throughout your application like so:

class Post extends AppModel {

    public function newest() {
        $model = $this;
        return Cache::remember('newest_posts', function() use ($model){
            return $model->find('all', array(
                'order' => 'Post.updated DESC',
                'limit' => 10
            ));
        }, 'longterm');
    }
}

The above will fetch the value associated with the key newest_posts from the cache if it exists. Otherwise, it will execute the function and SQL query, storing the result in the cache using the newest_posts key.

You can find much more information on how to use caching with CakePHP here.

WordPress

We support WordPress through two different options. The first you can find here, and uses the binary memcache protocol and is supported by us. It should be easy to install, simply follow the instructions on the Git repo.

We also have a community support alternative approach that uses the ASCII memcache protocol, which is far easier to get running on your own servers if you aren’t using a hosted platform like Heroku. You can find it on GitHub here. Please follow the instructions on the repo page.

Node.js

For Node.js we recommend the use of the memjs client library. It is written and supported by MemCachier itself! To install, use npm:

$ npm install memjs

Using it is straight-forward as memjs understands the MEMCACHIER_SERVERS, MEMCACHIER_USERNAME and MEMCACHIER_PASSWORD environment variables that the MemCachier add-on setups. For example:

var memjs = require('memjs')

var mc = memjs.Client.create(process.env.MEMCACHIER_SERVERS, {
  failover: true,  // default: false
  timeout: 1,      // default: 0.5 (seconds)
  keepAlive: true  // default: false
})

mc.set('hello', 'memcachier', {expires:0}, function(err, val) {
  if(err != null) {
    console.log('Error setting value: ' + err)
  }
})

mc.get('hello', function(err, val) {
  if(err != null) {
    console.log('Error getting value: ' + err)
  }
  else {
    console.log(val.toString('utf8'))
  }
})

Java

For Java we recommend using the XMemcached client. There is also the SpyMemcached client which we have recommended in the past. Many MemCachier customers reported problems with SpyMemcached in the presence of network issues. SpyMemcached seems to have trouble coping with connection timeouts or resets. For this reason we now recommend XMemcached.

We also recommend using Apache Maven or Gradle as a build tool. Here we show the dependancy configuration for Maven but they are similar for Gradle. If you aren’t using Maven or Gradle and are instead using Apache Ant or your own build system, then simply add the xmemcached or spymemcached jar file as a dependency of your application.

XMemcached

To use XMemcached with Maven you need to add the xmemcached library to your dependencies in your pom.xml file:

<dependency>
  <groupId>com.googlecode.xmemcached</groupId>
  <artifactId>xmemcached</artifactId>
  <version>2.4.3</version>
</dependency>

If you are using a version older than 2.4.3, please update to the latest version as it contains important bug fixes.

Once your build system is configured, you can start adding caching to your Java app:

import net.rubyeye.xmemcached.MemcachedClient;
import net.rubyeye.xmemcached.MemcachedClientBuilder;
import net.rubyeye.xmemcached.XMemcachedClientBuilder;
import net.rubyeye.xmemcached.auth.AuthInfo;
import net.rubyeye.xmemcached.command.BinaryCommandFactory;
import net.rubyeye.xmemcached.exception.MemcachedException;
import net.rubyeye.xmemcached.utils.AddrUtil;

import java.lang.InterruptedException;
import java.net.InetSocketAddress;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeoutException;

public class App {
  public static void main( String[] args ) {
    List<InetSocketAddress> servers =
      AddrUtil.getAddresses(System.getenv("MEMCACHIER_SERVERS").replace(",", " "));
    AuthInfo authInfo =
      AuthInfo.plain(System.getenv("MEMCACHIER_USERNAME"),
                     System.getenv("MEMCACHIER_PASSWORD"));

    MemcachedClientBuilder builder = new XMemcachedClientBuilder(servers);

    // Configure SASL auth for each server
    for(InetSocketAddress server : servers) {
      builder.addAuthInfo(server, authInfo);
    }

    // Use binary protocol
    builder.setCommandFactory(new BinaryCommandFactory());
    // Connection timeout in milliseconds (default: )
    builder.setConnectTimeout(1000);
    // Reconnect to servers (default: true)
    builder.setEnableHealSession(true);
    // Delay until reconnect attempt in milliseconds (default: 2000)
    builder.setHealSessionInterval(2000);

    try {
      MemcachedClient mc = builder.build();
      try {
        mc.set("foo", 0, "bar");
        String val = mc.get("foo");
        System.out.println(val);
      } catch (TimeoutException te) {
        System.err.println("Timeout during set or get: " +
                           te.getMessage());
      } catch (InterruptedException ie) {
        System.err.println("Interrupt during set or get: " +
                           ie.getMessage());
      } catch (MemcachedException me) {
        System.err.println("Memcached error during get or set: " +
                           me.getMessage());
      }
    } catch (IOException ioe) {
      System.err.println("Couldn't create a connection to MemCachier: " +
                         ioe.getMessage());
    }
  }
}

You may wish to look the xmemcached Wiki or JavaDocs.

SpyMemcached

We’ve built a small Java example, using SpyMemcached with Jetty. Source code or Deploy.

To use SpyMemcached with Maven you need to add the spymemcached library to your dependencies in your pom.xml file:

<dependency>
  <groupId>spy</groupId>
  <artifactId>spymemcached</artifactId>
  <version>2.12.3</version>
  <scope>provided</scope>
</dependency>

Once your build system is configured, you can start adding caching to your Java app:

import java.io.IOException;
import net.spy.memcached.AddrUtil;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.ConnectionFactoryBuilder;
import net.spy.memcached.auth.PlainCallbackHandler;
import net.spy.memcached.auth.AuthDescriptor;

public class Foo {
  public static void main(String[] args) {
    AuthDescriptor ad = new AuthDescriptor(
        new String[] { "PLAIN" },
        new PlainCallbackHandler(System.getenv("MEMCACHIER_USERNAME"),
                                 System.getenv("MEMCACHIER_PASSWORD")));
    try {
      MemcachedClient mc = new MemcachedClient(
          new ConnectionFactoryBuilder()
              .setProtocol(ConnectionFactoryBuilder.Protocol.BINARY)
              .setAuthDescriptor(ad).build(),
          AddrUtil.getAddresses(System.getenv("MEMCACHIER_SERVERS")));

      mc.set("foo", 0, "bar");
      System.out.println(mc.get("foo"));
    } catch (IOException ioe) {
      System.err.println("Couldn't create a connection to MemCachier: \nIOException "
              + ioe.getMessage());
    }
  }
}

For convenience, you may want to set the above code up as a new MemCachierClient class:

package com.memcachier.examples.java;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.List;

import javax.security.auth.callback.CallbackHandler;

import net.spy.memcached.ConnectionFactory;
import net.spy.memcached.ConnectionFactoryBuilder;
import net.spy.memcached.MemcachedClient;
import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.auth.PlainCallbackHandler;

public class MemCachierClient extends MemcachedClient {

   public MemCachierClient(String username, String password, String servers) throws IOException {
       this(new SASLConnectionFactoryBuilder().build(username, password), getAddresses(servers));
   }

   public MemCachierClient(ConnectionFactory cf, List<InetSocketAddress> addrs) throws IOException {
       super(cf, addrs);
   }

   private static List<InetSocketAddress> getAddresses(String servers) {
       List<InetSocketAddress> addrList = new ArrayList<InetSocketAddress>();
       for (String server : servers.split(",")) {
           String addr = server.split(":")[0];
           int port = Integer.parseInt(server.split(":")[1]);
           addrList.add(new InetSocketAddress(addr, port));
       }
       return addrList;
   }
}

class SASLConnectionFactoryBuilder extends ConnectionFactoryBuilder {
   public ConnectionFactory build(String username, String password){
       CallbackHandler ch = new PlainCallbackHandler(username, password);
       AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"}, ch);
       this.setProtocol(Protocol.BINARY);
       this.setAuthDescriptor(ad);
       return this.build();
   }
}

It is possible that you will run into Java exceptions about the class loader. (See Spymemcached issue 155. The reported issue also contains a suggested work around.

You may wish to look the spymemcached JavaDocs or some more example code to help in using MemCachier effectively. There is also a guide on using WebRunner, Heroku’s framework to handle sessions with MemCachier.

Spring Boot

We’ve built a small Spring Boot example. Source code or Deploy.
We also have a tutorial on using Spring Boot with MemCachier here.

In order to use memcache in Spring you can use simple-spring-memcached. It works with both, the XMemcached (recommended) or the SpyMemcached client.

Simple Spring XMemcached

We recommend you use Simple Spring Memcached with the XMemcached client. In order to do so you need to add the respective dependencies to your pom.xml:

<dependency>
  <groupId>com.google.code.simple-spring-memcached</groupId>
  <artifactId>xmemcached-provider</artifactId>
  <version>4.0.0</version>
</dependency>
<dependency>
  <groupId>com.googlecode.xmemcached</groupId>
  <artifactId>xmemcached</artifactId>
  <version>2.4.3</version>
</dependency>

For version 4.0.0 of simple-spring-memcached it is important that you explicitly import XMemcached version 2.4.3 as it contains important bug fixes.

To configure Simple Spring Memcached with XMemcached, add the following configuration class to your application:

import java.net.InetSocketAddress;
import java.util.List;
import java.util.Map;
import java.util.HashMap;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.code.ssm.CacheFactory;
import com.google.code.ssm.config.AbstractSSMConfiguration;
import com.google.code.ssm.config.DefaultAddressProvider;
import com.google.code.ssm.providers.xmemcached.XMemcachedConfiguration;
import com.google.code.ssm.providers.xmemcached.MemcacheClientFactoryImpl;
import net.rubyeye.xmemcached.auth.AuthInfo;
import net.rubyeye.xmemcached.utils.AddrUtil;

@Configuration
public class MemCachierConfig extends AbstractSSMConfiguration {

  @Bean
  @Override
  public CacheFactory defaultMemcachedClient() {
    String serverString = System.getenv("MEMCACHIER_SERVERS").replace(",", " ");
    List<InetSocketAddress> servers = AddrUtil.getAddresses(serverString);
    AuthInfo authInfo = AuthInfo.plain(System.getenv("MEMCACHIER_USERNAME"),
                                       System.getenv("MEMCACHIER_PASSWORD"));
    Map<InetSocketAddress, AuthInfo> authInfoMap =
      new HashMap<InetSocketAddress, AuthInfo>();
    for(InetSocketAddress server : servers) {
      authInfoMap.put(server, authInfo);
    }

    final XMemcachedConfiguration conf = new XMemcachedConfiguration();
    conf.setUseBinaryProtocol(true);
    conf.setAuthInfoMap(authInfoMap);

    final CacheFactory cf = new CacheFactory();
    cf.setCacheClientFactory(new MemcacheClientFactoryImpl());
    cf.setAddressProvider(new DefaultAddressProvider(serverString));
    cf.setConfiguration(conf);
    return cf;
  }
}

Now you can use the Simple Spring Memcached annotations in your Spring application.

Simple Spring SpyMemcached

If you want to use Simple Spring Memcached with SpyMemcached you need to add the respective dependencies to your pom.xml:

<dependency>
  <groupId>com.google.code.simple-spring-memcached</groupId>
  <artifactId>spymemcached-provider</artifactId>
  <version>4.0.0</version>
</dependency>

To configure Simple Spring Memcached with SpyMemcached, add the following configuration class to your application:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.google.code.ssm.CacheFactory;
import com.google.code.ssm.config.AbstractSSMConfiguration;
import com.google.code.ssm.config.DefaultAddressProvider;
import com.google.code.ssm.providers.spymemcached.SpymemcachedConfiguration;
import com.google.code.ssm.providers.spymemcached.MemcacheClientFactoryImpl;
import net.spy.memcached.auth.AuthDescriptor;
import net.spy.memcached.auth.PlainCallbackHandler;

@Configuration
public class MemCachierConfig extends AbstractSSMConfiguration {

  @Bean
  @Override
  public CacheFactory defaultMemcachedClient() {
    String serverString = System.getenv("MEMCACHIER_SERVERS");
    AuthDescriptor ad = new AuthDescriptor(new String[] { "PLAIN" },
                new PlainCallbackHandler(System.getenv("MEMCACHIER_USERNAME"),
                                         System.getenv("MEMCACHIER_PASSWORD")));

    final SpymemcachedConfiguration conf = new SpymemcachedConfiguration();
    conf.setUseBinaryProtocol(true);
    conf.setAuthDescriptor(ad);

    final CacheFactory cf = new CacheFactory();
    cf.setCacheClientFactory(new MemcacheClientFactoryImpl());
    cf.setAddressProvider(new DefaultAddressProvider(serverString));
    cf.setConfiguration(conf);
    return cf;
  }
}

Now you can use the Simple Spring Memcached annotations in your Spring application.

Use Simple Spring Memcached annotations

To apply caching to functions Simple Spring Memcached provides three main types of annotations:

  1. @ReadThrough*Cache tries to get a value from the cache. If it does not exist it will execute the function and store the return value in the cache to make sure it is available the next time the function is called.
  2. @Invalidate*Cache deletes key value pairs from the cache.
  3. @Update*Cache updates the values for stored keys.

Each type of annotation comes in 3 flavors (to replace the * above):

  1. Single applies the caching method to a single key that is specified by a parameter of the annotated function marked with the @ParameterValueKeyProvider annotation.
  2. Multi applies the caching method to a collection of keys and works the same as Single but the annotated parameter needs to be a Collection.
  3. Assign applies the caching method to an assigned key defined within the annotation.

These 9 annotations are the meat of Simple Spring Memacached but it offers more annotations to aid your caching needs. For more information consult the Simple Spring Memcached documentation.

Some examples

  • Probably the most used annotation is @ReadThroughSingleCache. It caches the result of complex computation with a key depending on the namespace and the input value. The cached value never expires.
  @ReadThroughSingleCache(namespace = "ComplexComuptation", expiration = 0)
  public ComplexSerializableResult compute(@ParameterValueKeyProvider Long input) {
    // ...
    return result;
  }
  • It is important to delete stale data and @InvalidateAssignCache does exactely that for a given key:
  @InvalidateAssignCache(namespace = "TableA", assignedKey = "SumOfColumnX")
  public void saveValueToTableA(TableAObject value) {
    //...
  }

More examples can be found in the Simple Spring Memcached documentation.

Use Spring Caching integration

Spring also has native caching annotations and simple-spring-memcached can be configured so Spring’s integrated caching is backed by memcache. While it is a good idea to use Spring’s caching integration if you want the flexibility to change the underlying store at any time, we generally recommend using the annotations provided by Simple Spring Memcached as they are specifically designed to be used with Memcache.

Enabling memcache for Spring’s cache integration requires an additional dependency in your pom.xml file:

<dependency>
  <groupId>com.google.code.simple-spring-memcached</groupId>
  <artifactId>spring-cache</artifactId>
  <version>4.0.0</version>
</dependency>

To use these annotations you need create a CacheManager bean and set the @EnableCaching annotation. Concretely, extend the MemCachierConfig shown above as follows:

// ...
import java.util.Arrays;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cache.CacheManager;
import com.google.code.ssm.Cache;
import com.google.code.ssm.spring.ExtendedSSMCacheManager;
import com.google.code.ssm.spring.SSMCache;

@EnableCaching
@Configuration
public class MemCachierConfig extends AbstractSSMConfiguration {

  @Bean
  @Override
  public CacheFactory defaultMemcachedClient() {
    // ...
  }

  @Bean
  public CacheManager cacheManager() throws Exception {
    // Use SSMCacheManager instead of ExtendedSSMCacheManager if you do not
    // need to set per key expiration
    ExtendedSSMCacheManager cacheManager = new ExtendedSSMCacheManager();
    Cache cache = this.defaultMemcachedClient().getObject();
    // SSMCache(cache, 0, false) creates a cache with default key expiration
    // of 0 (no expiration) and flushing disabled (allowClear = false)
    cacheManager.setCaches(Arrays.asList(new SSMCache(cache, 0, false)));
    return cacheManager;
  }
}

Now you can use Spring’s caching annotations, most importantly @Cacheble, @CacheEvict, and @CachePut.

Note: Spring’s annotations require a cache name. The default cache name configured by Simple Spring Memcached is "default".

  • @Cacheable performs similarly to the @ReadThrough*Cache annotations explained above: it tries to get a value from the cache but if unavailable, it will execute the function and store the result for future calls to this function with the given parameters.
  @Cacheable("default#3600")
  public ComplexSerializableResult compute(Long input) {
    // ...
    return result;
  }

@Cacheable does not have native support setting expiration times. However, if you use the ExtendedSSMCacheManager you can set an expriation time by appending #<seconds> to the cache name. The example above sets the expiration to one hour. Omitting this appendix falls back to the configured default expiration time.

  • @CacheEvict deletes a value from the cache. This is important to get rid of stale data.
  @CacheEvict("default")
  public void updateValue(ValueId id) {
    //...
  }
  • @CachePut allows you to add values to the cache and is a great way to optimize your cache. It supports the same options as the @Cacheable annotation.
  @CachePut("default")
  public Value updateValue(ValueId id) {
    //...
    return value;
  }

For more information on these caching annotations and their options consult Spring’s caching documentation and the Spring Caching Integration secion of the Simple Spring Memcached documentation.

Go

Here we explain how you setup and use MemCachier in Go.

We recommend the mc memcache client. It supports the binary protocol and SASL authentication and was specifically designed to work well with MemCachier. However, if you prefer to use gomemcache we have a fork of gomemcache that works with MemCachier.

Recommended client: mc

This client is supports the binary protocol and SASL authentication and is maintained by MemCachier. To install it run:

$ go get github.com/memcachier/mc

Next, configure your memcached client in the following way:

username := os.Getenv("MEMCACHIER_USERNAME")
password := os.Getenv("MEMCACHIER_PASSWORD")
server := os.Getenv("MEMCACHIER_SERVERS")

c := mc.NewMC(server, username, password)
defer c.Quit()

This will create a memcache client with default parameters. If you prefer, you can also configure the memcache client like so:

username := os.Getenv("MEMCACHIER_USERNAME")
password := os.Getenv("MEMCACHIER_PASSWORD")
server := os.Getenv("MEMCACHIER_SERVERS")

config := mc.DefaultConfig()
config.Hasher = mc.NewModuloHasher()         // default
config.Retries = 2                           // default
config.RetryDelay = 200 * time.Millisecond   // default
config.Failover = true                       // default
config.ConnectionTimeout = 2 * time.Second   // default
config.DownRetryDelay = 60 * time.Second     // default
config.PoolSize = 1                          // default
config.TcpKeepAlive = true                   // default
config.TcpKeepAlivePeriod = 60 * time.Second // default
config.TcpNoDelay = true                     // default
c := mc.NewMCwithConfig(server, username, password, config)
defer c.Quit()

After this, you can start writing cache code in your app:

exp := 0 // seconds if less than 30 days, unix timestamp if more
flags := 0
cas := 0
_, err := c.Set("foo", "bar", flags, exp, cas)
if err != nil {
    fmt.Printf("Failed to set value: %s\n", err)
}

val, _, _, err := c.Get("foo")
if err != nil {
    fmt.Printf("Failed to fetch value: %s\n", err)
}
fmt.Printf("Got value: %s\n", val)

Alternative client: gomemcache

We highly recommed to use the mc client since it was designed to work well with MemCachier but using gomemcache is also possilbe. While gomemcache is a popular memcache client it only supports the ASCII protocol. We have a fork that allows you to use this client with MemCachier anyway.

To install our version of gomemcache:

$ go get github.com/memcachier/gomemcache

Next, configure your memcached client in the following way:

username := os.Getenv("MEMCACHIER_USERNAME")
password := os.Getenv("MEMCACHIER_PASSWORD")
servers := os.Getenv("MEMCACHIER_SERVERS")

mc := memcache.New(strings.Split(servers, ",")...)
mc.SetAuth(username, []byte(password))

After this, you can start writing cache code in your app:

err := mc.Set(&memcache.Item{Key: "foo", Value: []byte("my value")})
if err != nil {
    fmt.Printf("Failed to set value: %s\n", err)
}

val, err := mc.Get("foo")
if err != nil {
    fmt.Printf("Failed to fetch value: %s\n", err)
}
fmt.Printf("Got value: %s\n", val)

Gin

We’ve built a small Gin example. Source code or Deploy.
We also have a tutorial on using Gin and MemCachier together here.

In Gin you can use the standard mc interface to get and set values as described in our Go documentation to cache results of expensive computations or database queries:

package main

import (
  "os"
  "fmt"
  "github.com/memcachier/mc"
)

func main() {
  username := os.Getenv("MEMCACHIER_USERNAME")
  password := os.Getenv("MEMCACHIER_PASSWORD")
  servers := os.Getenv("MEMCACHIER_SERVERS")

  mcClient := mc.NewMC(servers, username, password)
  defer mcClient.Quit()

  _, err := mcClient.set("foo", "bar", 0, 0, 0)
  if err != nil {
    fmt.Printf("Failed to set value: %s\n", err)
  }

  val, _, _, err := c.Get("foo")
  if err != nil {
    fmt.Printf("Failed to fetch value: %s\n", err)
  }
  fmt.Printf("Got value: %s\n", val)
}

In addition there are two Gin specific ways to use Memcache:

  1. Cache rendered views
  2. Store sessions

Cache rendered views

To cache rendered views you need the gin-contrib/cache library. Now you can use the CachePage middleware like so:

package main

import (
  "os"
  "github.com/gin-gonic/gin"
  "github.com/gin-contrib/cache"
  "github.com/gin-contrib/cache/persistence"
)

func main() {
    username := os.Getenv("MEMCACHIER_USERNAME")
  password := os.Getenv("MEMCACHIER_PASSWORD")
  servers := os.Getenv("MEMCACHIER_SERVERS")

  mcStore := persistence.NewMemcachedBinaryStore(servers, username, password, persistence.FOREVER)

    router := gin.New()
  router.GET("/", cache.CachePage(mcStore, persistence.DEFAULT, func(c *gin.Context) {
    // ...
  }))
}

Whenever the view changes, e.g., when the content changes, you need to make sure to invalidate the cached view so it will be re-rendered. This can be done by deleting the cached item (for the root route in this case):

mcStore.Delete(cache.CreateKey("/"))

Storing Sessions in Memcache

On Heroku it is a good idea to store sessions in Memcache instead of in a file on disk for two reasons:

  1. Dynos only have an ephemeral filesystem that is not persisted across restarts.
  2. You might have multiple dynos which will not share the same ephemeral filesystem.

Memcache works well for sessions that time out, however, since Memcache is a cache and thus not persistent, saving long-lived sessions in Memcache might not be ideal. For long-lived sessions consider a permanent storage option such as your database.

To use sessions in Gin you need gin-contrib/session. You can easily add it to your Gin app like so:

package main

import (
  "os"
  "github.com/memcachier/mc"
  "github.com/gin-contrib/sessions"
  "github.com/gin-contrib/sessions/memcached"
)

func main() {
    username := os.Getenv("MEMCACHIER_USERNAME")
  password := os.Getenv("MEMCACHIER_PASSWORD")
  servers := os.Getenv("MEMCACHIER_SERVERS")

  mcClient := mc.NewMC(servers, username, password)
  defer mcClient.Quit()

    router := gin.New()
  sessionStore := memcached.NewMemcacheStore(mcClient, "", []byte("secret"))
  router.Use(sessions.Sessions("mysession", sessionStore))
}

Rust

For Rust we recommend the use of the memcached-rs client library. Since version 0.4 it supports SASL authentication and can be used to connect to MemCachier.

Using memcached-rs requires the MEMCACHIER_SERVERS, MEMCACHIER_USERNAME and MEMCACHIER_PASSWORD environment variables that the MemCachier add-on setups.

The setup looks as follows:

extern crate memcached;

use std::env;

use memcached::proto::{Operation, ProtoType};
use memcached::Client;

fn main() {
    let servers = env::var("MEMCACHIER_SERVERS").unwrap();
    let username = env::var("MEMCACHIER_USERNAME").unwrap();
    let password = env::var("MEMCACHIER_PASSWORD").unwrap();


    let mut client = Client::connect_sasl(servers.split(',').map(|s| format!("{}{}", "tcp://", s))
                                                            .map(|s| (s, 1))
                                                            .collect::<Vec<(String, usize)>>()
                                                            .as_slice(),
                                          ProtoType::Binary,
                                          &username, &password).unwrap();

    client.set(b"hello", b"MemCachier", 0xdeadbeef, 2).unwrap();
    let (value, flags) = client.get(b"hello").unwrap();


    println!("Got: {}", std::str::from_utf8(&value).unwrap());
    assert_eq!(&value[..], b"MemCachier");
    assert_eq!(flags, 0xdeadbeef);
}

Client library support

MemCachier will work with any memcached binding that supports SASL authentication and the binary protocol. In the following you can find a list of all clients known to us including a description of their most important features. This list is by no means exhaustive and if you know of a client not on this list, don’t hesitate to contact us. All clients marked as supported have been tested with our service.

Clojure

Library Supported Binary protocol SASL authentication Cluster support
Xmemcached yes yes yes yes

Go

Library Supported Binary protocol SASL authentication Cluster support
mc yes yes yes yes
gomemcache limited1 no limited1 yes
gomemcached ? yes yes no
memcache2 no no no yes
gomemcache (zeayes) no yes no yes

1 We have a fork that does ASCII auth and an outstanding PR in the main repository. 2 A high performance fork of gomemcache.

Haskell

Library Supported Binary protocol SASL authentication Cluster support
memcache yes yes yes ?
memcached ? ? ? ?

Java

Library Supported Binary protocol SASL authentication Cluster support
Xmemcached yes yes yes yes
spymemcached (mirror) yes yes yes yes
Memcached-Java-Client no yes no ?
Folsom ? yes no ?

Node.js

Library Supported Binary protocol SASL authentication Cluster support
memjs yes yes yes yes
memcached no no no ?
memcache no no no ?

PHP

Library Supported Binary protocol SASL authentication Cluster support
php-memcached1 yes yes yes yes
php-memcache-sasl yes yes yes yes
memcached.php ? no no ?
php-memcache no yes yes ?

1 Requires libmemcached.

Python

Library Supported Binary protocol SASL authentication Cluster support
pylibmc1 yes yes yes yes
python-binary-memcached yes yes yes yes
python-memcached no no no ?
pymemcache no no no no
ultramemcache2 no no no ?

1 Requires libmemcached. 2 C++ bindings.

Ruby

Library Supported Binary protocol SASL authentication Cluster support
dalli yes yes yes yes
memcached1 ? ? ? ?

1 Requires libmemcached.

Rust

Library Supported Binary protocol SASL authentication Cluster support
memcache no yes no ?
bmemcached no yes no ?
memcached-rs no yes no ?

Scala

Library Supported Binary protocol SASL authentication Cluster support
Shade yes yes yes ?
memcontinuationed no no no ?

Sample applications

We’ve built a number of working sample apps, too. Keep in mind they expect MEMCACHIER_SERVERS, MEMCACHIER_USERNAME, and MEMCACHIER_PASSWORD to be in the environment.

  • Sinatra (Heroku)
  • Rails (Heroku)
  • Rack::Cache (Heroku)
  • Django (Heroku)
  • PHP (Heroku)
  • Node.js (Heroku)
  • Java (Heroku)
  • Flask (Heroku)
  • Gin (Heroku)
  • Spring Boot (Heroku)
  • Express.js (Heroku)
  • Laravel (Heroku)

We also have a collection of example code that can be a useful reference source.

Local usage

To test your Heroku application locally, you will need to run a local memcached server. MemCachier can only run in Heroku, but because MemCachier and memcached speak the same protocol, you shouldn’t have any issues testing locally. Installation depends on your platform.

This will install memcached without SASL authentication support. This is generally what you want as client code can still try to use SASL auth and memcached will simply ignore the requests which is the same as allowing any credentials. So your client code can run without modification locally and on Heroku.

On Ubuntu:

$ sudo apt-get install memcached

On OS X (with Homebrew):

$ brew install memcached

For Windows you will need to build memcached from source.

For further information and resources (such as the memcached source code) please refer to the Memcache.org homepage

To run memcached simply execute the following command:

$ memcached -v

MemCachier analytics

Our analytics dashboard is a simple tool that gives you more insight into how you’re using memcache. Here’s a screenshot of the dashboard:

Analytics Dashboard

To access your application’s analytics dashboard run:

$ heroku addons:open memcachier

The analytics displayed are:

  • Limit – Your current cache size and memory limit. Once usage comes close to this amount you will start seeing evictions.
  • Live Connections – Number of connections currently open to your cache.
  • Total connections – Number of connections ever made to your cache. (So always larger than live connections).
  • Items – Number of items currently stored in your cache.
  • Evictions – Number of items ever evicted from your cache due to memory pressure. Items are evicted in an LRU order.
  • New Evictions – Number of evictions that have occured since the last time we sampled your cache.
  • Hit Rate – The ratio of get commands that return an item (hit) vs. the number that return nothing (miss). This ratio is for the period between now and when we last sampled your cache.
  • Set Cmds – Number of times you have ever performed a set command.
  • Flush Cmds – Number of times you have ever performned a flush command.

With the basic analytics dashboard we sample your cache once per hour. With the advance dashboard we sample it once every 30 minutes.

Advanced analytics

We offer higher paying customers an advance version of our analytics dashboard. Currently, this offers two primary advantages:

  • Higher Sample Rate – We sample the cache for collecting analytics once every thirty minutes, twice the rate of the basic analytics dashboard. We don’t sample more often than that as a higher granularity hasn’t proven to be useful, it leads to more noise and less signal.
  • More Graphs – We offer two additional graphs for the advanced analytics dashboard.
    • Eviction Graph – Your new evictions tracked over time.
    • Connection Graph – Your new connecions tracked over time.

Please note that our graph only allows two data sources to be selected at a time. So if two are already selected, say “Usage” and “Hit Rate”, to select a different data source, say “Evictions”, you’ll need to deselect an existing data source first before selecting the new one to display.

Analytics API

You can also access features available on the analytics dashboard via the API.

  • Authenticate
  • Memcachier API ID
  • Stats
  • History
  • Flush
  • List Credentials
  • Create Credentials
  • Update Credentials
  • Promote Credentials
  • Delete Credentials

Authentication

Memcachier uses credentials to allow access to the API. After you’ve created a cache, you can find your credentials on the analytics dashboard. Only credentials that have the API capability will be allowed to use this API.

Memcachier expects for your credentials to be included in the header of all API requests.

curl "https://analytics.memcachier.com/api/v1/:memcachier_id/:action"
  --user CRED_USERNAME:CRED_PASSWORD

Make sure to replace CRED_USERNAME:CRED_PASSWORD with your credential username and password found on the analytics dashboard.

Memcachier API ID

All of the API paths include a <memcachier_id> variable. In order to find this ID, you’ll need to use the /login path.

This is not the same thing as the “Memcachier ID” listed on your analytics dashboard.

HTTP Request

GET https://analytics.memcachier.com/api/login

Response

Status Response
200 JSON response with memcachier ID
403 “You are not authorized to perform this action.”
404 “No cache found.”
500 “Server error”

Example:

curl "https://analytics.memcachier.com/api/v1/login"
  --user CRED_USERNAME:CRED_PASSWORD

Returns:

{
    "cache_id": 1561
}

Stats

This endpoint retrieves all the statistics for your cache.

HTTP Request

GET https://analytics.memcachier.com/api/v1/<memcachier_id>/stats

Response

Status Response
200 JSON response with stats
403 “You are not authorized to perform this action.”
500 “Server error: a.b.c.totallyaserver.com:1234,…”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/stats"
  --user "CRED_USERNAME:CRED_PASSWORD"

Returns:

{
    "a.b.c.totallyaserver.com:12345": {
        "auth_cmds": 19,
        "auth_errors": 0,
        "bytes": 0,
        "bytes_read": 960,
        "bytes_written": 22233,
        "cas_badval": 0,
        "cas_hits": 0,
        "cas_misses": 0,
        "cmd_delete": 0,
        "cmd_flush": 0,
        "cmd_get": 0,
        "cmd_set": 0,
        "cmd_touch": 0,
        "curr_connections": 0,
        "curr_items": 0,
        "decr_hits": 0,
        "decr_misses": 0,
        "delete_hits": 0,
        "delete_misses": 0,
        "evictions": 0,
        "expired": 0,
        "get_hits": 0,
        "get_misses": 0,
        "incr_hits": 0,
        "incr_misses": 0,
        "limit_maxbytes": 28835840,
        "time": 1500651085,
        "total_connections": 19,
        "total_items": 0,
        "touch_hits": 0,
        "touch_misses": 0
    }
}

History

This endpoint retrieves the statistical history of a cache.

HTTP Request

GET https://analytics.memcachier.com/api/v1/<memcachier_id>/history

Response

Status Response
200 JSON response with historical stats
403 “You are not authorized to perform this action.”
500 “Server error”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/history"
  --user "CRED_USERNAME:CRED_PASSWORD"

Returns:

  [{
    "memcachier_id": "11",
    "server": "a.b.c.totallyaserver.memcachier.com",
    "stats": {
        "auth_cmds": 158,
        "auth_errors": 0,
        "bytes": 0,
        "bytes_read": 3840,
        "bytes_written": 178754,
        "cas_badval": 0,
        "cas_hits": 0,
        "cas_misses": 0,
        "cmd_delete": 0,
        "cmd_flush": 0,
        "cmd_get": 0,
        "cmd_set": 0,
        "cmd_touch": 0,
        "curr_connections": 2,
        "curr_items": 0,
        "decr_hits": 0,
        "decr_misses": 0,
        "delete_hits": 0,
        "delete_misses": 0,
        "evictions": 0,
        "expired": 0,
        "get_hits": 0,
        "get_misses": 0,
        "incr_hits": 0,
        "incr_misses": 0,
        "limit_maxbytes": 1153433600,
        "time": 1490731542,
        "total_connections": 158,
        "total_items": 0,
        "touch_hits": 0,
        "touch_misses": 0
    },
    "timestamp": "1490731541096"
    }, … ]

Flush

This endpoint will flush all of the data from the cache cache.

HTTP Request

POST https://analytics.memcachier.com/api/v1/<memcachier_id>/flush

Response

Status Response
200 “”
403 “You are not authorized to perform this action.”
500 “Server error: a.b.c.totallyaserver.com:1234,…”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/flush" -X POST
  --user "CRED_USERNAME:CRED_PASSWORD"

Certain credentials may not have permission to flush the cache, which will produce a 403 error.

List Credentials

The endpoint returns a list of all the credentials connected to the cache.

HTTP Request

GET https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials

Response

Status Response
200 JSON list of credentials
403 “You are not authorized to perform this action.”
500 “Server error”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials"
  --user "CRED_USERNAME:CRED_PASSWORD"

Returns:

  [
    {
        "cache_id": 14,
        "flush_capability": false,
        "id": 44,
        "sasl_username": "CRED_USERNAME",
        "uuid": null,
        "write_capability": true,
        "api_capability": true,
        "primary": true,
    },
    {
        "cache_id": 14,
        "flush_capability": false,
        "id": 43,
        "sasl_username": "789101",
        "uuid": null,
        "write_capability": true,
        "api_capability": true,
        "primary": false,
    }, ...
]

Create Credentials

This endpoint creates a new set of credentials which can be used to connect to the cache.

HTTP Request

POST https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials

Response

Status Response
200 JSON of new credential set
403 “You are not authorized to perform this action.”
500 “Server error”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials" -X POST
  --user "CRED_USERNAME:CRED_PASSWORD"

Returns:

{
    "cache_id": 14,
    "id": null,
    "sasl_password": "CRED_PASSWORD",
    "sasl_username": "CRED_USERNAME",
    "uuid": null,
    "primary": false,
    "flush_capability": true,
    "write_capability": true,
    "api_capability": true,
}

Update Credentials

This endpoint updates the capabilities of a specific set of credentials.

HTTP Request

POST https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials/<cred_id>

Query Parameters

Parameter Default Description
flush_capability true Authorize this set of credentials to flush the cache.
write_capability true Authorize this set of credentials to write to the cache.
api_capability true Authorize this set of credentials to use this API.

Response

Status Response
200 JSON of new credential properties
403 “You are not authorized to perform this action.”
500 “Server error”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials/<cred_username>" -X PATCH
  -d '{"flush_capability":"false"}'
  --user "CRED_USERNAME:CRED_PASSWORD"

Returns:

{
    "flush_capability": false,
    "write_capability": true,
    "api_capability": true,
}

Promote Credentials

This endpoint promotes a set of credentials to primary.

HTTP Request

POST https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials/primary/<cred_id>

Response

Status Response
200 JSON of promoted credential set
403 “You are not authorized to perform this action.”
500 “Server error”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials/primary/<cred_username>" -X POST
  --user "CRED_USERNAME:CRED_PASSWORD"

Returns:

{
    "cache_id": 14,
    "id": null,
    "sasl_username": "CRED_USERNAME",
    "uuid": null,
    "primary": true,
    "flush_capability": false,
    "write_capability": true,
    "api_capability": true,
}

Delete Credentials

This endpoint deletes a set of credentials

HTTP Request

POST https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials/primary/<cred_id>

Response

Status Response
200 “”
403 “You are not authorized to perform this action.”
500 “Server error”

Example:

curl "https://analytics.memcachier.com/api/v1/<memcachier_id>/credentials/primary/<cred_username>" -X DELETE
  --user "CRED_USERNAME:CRED_PASSWORD"

New Relic integration

MemCachier supports integration with your New Relic dashboard if you happen to be a customer of both MemCachier and New Relic. Currently this feature is only available to caches of 500MB or larger. A blog post showing the integration can be found here.

To setup the integration you will need to find your New Relic license key. This can be done by going to your “Account Settings” page when logged in to New Relic by click on your New Relic username in the top right corner. Then you will find your license key in the right side information column. It should be exactly 40 characters long. Please refer to the blog post for a visual walkthrough.

Once you have your New Relic licence key, it can be entered for your cache on the analytics dashboard page. In the bottom right corner there is a button to do this.

Credentials

In order to connect a memcache client to MemCachier, you use a username and password listed on the analytics dashboard for your cache. Each cache can have multiple sets of credentials. One of these sets of credentials is distinguished as primary, meaning that it is linked to the Heroku MemCachier addon.

From the Credentials panel on the analytics dashboard, it is possible to create new credentials, delete existing credentials and promote secondary credentials to primary credentials. This makes it possible to rotate credentials by creating a new set of secondary credentials and promoting them to primary. Promoting a set of secondary credentials to primary causes an update of the MEMCACHIER_USERNAME and MEMCACHIER_PASSWORD configuration variables on your Heroku app and a restart of your dynos to pick up the new values.

Each set of credentials for a cache can be given different capabilities, in the sense that sets of credentials can be restricted to read-only access to the cache, or prevented from flushing the cache via the memcache API. These capabilities are controlled by checkboxes on the Credentials panel of the analytics dashboard. (The exact error conditions that a client will receive if it attempts to perform an action for which it does not have the capability depends on the details of the client library used. The most common cases are likely to be for the Dalli Ruby library and the pylibmc Python library. For both of these client libraries, attempting to set a cache entry using credentials that do not have the write capability will simply result in a “value not set” response from the library.)

Disabled Caches

Development caches are disabled after 30 days of inactivity. Disabled caches can no longer be accessed (authentication will fail). To use the caches again it can be re-enabled on the analytics dashboard under the Settings panel.

Encrypted Connections (TLS)

We generally don’t recommend using TLS to secure your connection. Why? Memcache is normally only used when performance is important and so low latency is critical. This means we expect your MemCachier cache and your application that accesses it runs in the same datacenter, for example the Amazon EC2 us-east-1 datacenter. All your traffic are running over, and only over, the internal datacenter network. This is a highly secure network that can’t be sniffed on or tampered with. For example, your web application is probably speaking HTTPS, but the HTTPS connection is very likely terminated at a load balancer, and then unsecured HTTP used to talk between the load balancer and your application.

It is possible to connect to MemCachier using TLS encrypted sockets. While no existing clients support TLS connections natively, we provide a buildpack for Heroku customers that proxies the connection to MemCachier and wraps it in a TLS connection. This can be useful for the extra paranoid among us, or to securely access your cache from outside the datacenter.

The buildpack installs and sets up stunnel on localhost listening on port 11211. It configures stunnel to connect to the MemCachier servers specified in your environment variable and to verify certificates as signed by the MemCachier Root CA.

Use the buildpack in conjunction with another buildpack that actually runs your app, using Heroku’s multiple buildpack feature:

$ heroku buildpacks:add https://github.com/memcachier/memcachier-tls-buildpack.git

Finally, configure your app to connect to localhost:11211 instead of using the MEMCACHIER_SERVERS environment variable, but, leave your MEMCACHIER_SERVERS environment variable unchanged as the TLS buildpack uses it to connect to MemCachier.

Upgrading and downgrading

Changing your plan, either by upgrading or downgrading, can be done easily at any time through Heroku.

  • No code changes are required.
  • Your cache won’t be lost or reset*.
  • You are charged by the hour for plans, so try experimenting with different cache sizes with low cost.

* When moving between the development plan to a production plan, you will loose your cache. This is unavoidable due to the strong separation between the development and production clusters.

Using MemCachier

Please refer to your client or framework documentation for how to use MemCachier effectively.

MemCachier Guides:

  • Advanced Memcache Usage
  • Building a Rails App with MemCachier
  • Scale Django with MemCachier
  • Scale Laravel with MemCachier
  • Scale Express.js with MemCachier
  • Rails + Rack::Cache + MemCachier
  • Java Webapp Runner Guide
  • Heroku’s Guide to Caching

Framework and Client Documentation:

  • Dalli (Ruby Client) API
  • Rails Caching Guide
  • PHP Memcached client
  • CakePHP Caching Guide
  • Pylibmc (Pytnon Client) API
  • Django Caching Guide
  • MemJS (node.js client) API
  • Spymemcached JavaDocs

Key-Value size limit (1MB)

MemCachier has a maximum size that a key-value object can be of 1MB. This applies to both key-value pairs created through a set command, or existing key-value pairs grown through the use of an append or prepend command. In the later case, the size of the key-value pair with the new data added to it, must still be less than 1MB.

The 1MB limit applies to the size of the key and the value together. A key of size 512KB with a value of 712KB would be in violation of the 1MB limit.

The reason for this has partially to do with how memory is managed in MemCachier. A limitation of the high performance design is a restriction on how large key-value pairs can become. Another reason is that storing values larger than 1MB doesn’t normally make sense in a high-performance key-value store. The network transfer time in these situations becomes the limiting factor for performance. A disk cache or even a database makes sense for this size value.

Errors about app trying to connect to localhost

By default, most memcache client look for the environment variables, MEMCACHE_SERVERS, MEMCACHE_USERNAME and MEMCACHE_PASSWORD for their configuration. These variables are used when the initialization code for the memcache client doesn’t specifically specify these values.

If these environment variables aren’t set, clients generally default to connecting to 127.0.0.1:11211 (i.e., localhost), with no username and password.

The MemCachier add-on sets the MEMCACHIER_SERVERS, MEMCACHIER_USERNAME and MEMCACHIER_PASSWORD environment variables. So you need to either set the equivalent MEMCACHE_* variables from these, or pass these values to your client when you create a new one in your code.

For example, pseudo-code for the first approach is:

env[MEMCACHE_SERVERS] = env[MEMCACHIER_SERVERS]
env[MEMCACHE_USERNAME] = env[MEMCACHIER_USERNAME]
env[MEMCACHE_PASSWORD] = env[MEMCACHIER_PASSWORD]

While pseudo-code for the second approach is:

memClient = new MemcacheClient(ENV['MEMCACHIER_SERVERS'],
                               ENV['MEMCACHIER_USERNAME'],
                               ENV['MEMCACHIER_PASSWORD'])

Please be careful that you have setup the your client in all locations. Many frameworks, such as Rails, use memcache in multiple ways and may require you to setup initialization properly in a few locations. Generally the first approach is preferred as it is global while the second approach is local to each initialization.

For example, with Ruby on Rails, you’ll need to setup cache_store, Rack::Cache and the session_store.

Support

All MemCachier support and runtime issues should be submitted via one of the Heroku Support channels. You can also reach us directly at support@memcachier.com. We encourage you to CC us on any urgent support tickets sent to Heroku.

Please include your MEMCACHIER_USERNAME with support tickets.

Any non-support related issues or product feedback is welcome via email at: support@memcachier.com.

Any issues related to MemCachier service are reported at MemCachier Status.

Please also follow us on twitter, @memcachier, for status and product announcements.

Keep reading

  • All Add-ons

Feedback

Log in to submit feedback.

Ziggeo mLab MongoDB

Information & Support

  • Getting Started
  • Documentation
  • Changelog
  • Compliance Center
  • Training & Education
  • Blog
  • Podcasts
  • Support Channels
  • Status

Language Reference

  • Node.js
  • Ruby
  • Java
  • PHP
  • Python
  • Go
  • Scala
  • Clojure

Other Resources

  • Careers
  • Elements
  • Products
  • Pricing

Subscribe to our monthly newsletter

Your email address:

  • RSS
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku Blog
    • Heroku News Blog
    • Heroku Engineering Blog
  • Heroku Podcasts
  • Twitter
    • Dev Center Articles
    • Dev Center Changelog
    • Heroku
    • Heroku Status
  • Facebook
  • Instagram
  • Github
  • LinkedIn
  • YouTube
Heroku is acompany

 © Salesforce.com

  • heroku.com
  • Terms of Service
  • Privacy
  • Cookies