MemCachier Now Recommends XMemcached for Java

If you’re using Memcache in Java, chances are you’re using the SpyMemcached client. It has been the most popular Java client for years. Unfortunately, at MemCachier we have had a lot of customer reports about problems with SpyMemcached. For this reason we now recommend to use XMemcached with Java.

What’s wrong with SpyMemcached?

The short answer is, we don’t really know. We got a lot of reports that hint at a race condition but we were never able to reproduce the problems consistently. The only reproducible issue we found was that SpyMemcached does not attempt to reconnect if a connection was terminated remotely. Sometimes we need to move customers to a different server (e.g., when a machine fails). In such cases SpyMemcached would not reconnect until the application was restarted. This issue definitely warrants a bug report and a fix. However, by the time we discovered it we already decided to switch to XMemcached due to the number of problem reports we have been getting.

How do I use XMemcached?

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

If you’re using Gradle then add the following to build.gradle:

repositories {
    mavenCentral()
}

dependencies {
    implementation 'com.googlecode.xmemcached:xmemcached:2.4.3'
}

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("MEMCACHED_SERVERS").replace(",", " "));
    AuthInfo authInfo =
      AuthInfo.plain(System.getenv("MEMCACHED_USERNAME"),
                     System.getenv("MEMCACHED_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 Memcached server: " +
                         ioe.getMessage());
    }
  }
}

The environment variables MEMCACHED_SERVERS, MEMCACHED_USERNAME, and MEMCACHED_PASSWORD contain a list of comma separated server addresses, your username, and password. If you use MemCachier as your memcached provider you can find these values in the cache overview page.

For more information such as how to use XMemcached with Spring Boot please consult our documentation.