Book Image

Getting Started with Memcached

By : Ahmed Soliman
Book Image

Getting Started with Memcached

By: Ahmed Soliman

Overview of this book

<p>Web application performance is no longer a non-functional requirement, but an implicit condition for an engaging user experience. As a result, responsive and highly scalable applications are becoming a necessity. Memcached is a high-performance distributed memory caching system built to speed up dynamic web applications by offloading pressure from your database. <br /><br />Getting Started with Memcached is a hands-on, comprehensive guide to the Memcached service and it’s API in different programming languages. It contains practical recipes to integrate Memcached within your Rails, Django, or even Scala Play! applications.<br /><br />This book will show you everything you need to know to start using Memcached in your existing or new web applications.<br />This book uses real-world recipes to help you learn how to store and retrieve data from your clustered virtual memory cache pool and how to integrate caching into your favourite web development framework.</p> <p><br />You will also learn how to build a Memcached consistent-hashing scalable cluster and how Memcached clients are properly configured to use different servers to scale out your memory cache pool in Ruby, Python, PHP, and Java. With this book, you will see how to cache templates and database queries in the most popular web development framework in use today.</p>
Table of Contents (9 chapters)

Using memcached with Java (Intermediate)


In this recipe, we will be using Java to talk to our memcached server. Java is a very powerful programming language and is famous for enterprise-class applications.

There are, of course, a variety of memcached clients written for Java. We have chosen the most powerful client that is not hard to use, that is spymemcached.

Getting ready

The spymemcached java library has artifacts published on the maven central repository. If you are using maven you will need to add this to your pom.xml file (highlighted):

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sample</groupId>
  <artifactId>spycache</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>spycache</name>
  <url>http://maven.apache.org</url>
  <dependencies>
   <dependency>
     <groupId>net.spy</groupId>
     <artifactId>spymemcached</artifactId>
     <version>2.10.1</version>
   </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

In my project here (named spycache), we will be showing snippets written inside the src/main/java/com/sample/ directory and to run the application you will need to run the mvn package.

Then after seeing BUILD SUCCESS you will need to run the application by using the following:

java -cp target/spycache-1.0-SNAPSHOT.jar com.sample.App

How to do it...

  1. Let's start by adding the following snippet into our main function:

          try {
              MemcachedClient client = new MemcachedClient(new InetSocketAddress("127.0.0.1", 11211));
              client.set("city", 20, "Istanbul");
    
              System.out.println((String)client.get("city"));
    
              client.shutdown();
            } catch (IOException e) {
               e.printStackTrace();
            }
  2. We have just created a connection and did a simple set/get operation. Let's now store a more complex object:

    class Employee implements Serializable{
      private static final long serialVersionUID = 2620538145665245947L;
      private String name;
      private int age;
      
      public Employee(String name, int age) {
        this.name = name;
        this.age = age;
      }
    
      public String getName() {
        return name;
      }
    
      public void setName(String name) {
        this.name = name;
      }
    
      public int getAge() {
        return age;
      }
    
      public void setAge(int age) {
        this.age = age;
      }
      @Override
      public String toString() {
         return "Employee(\"" + name + "\", " + age + ")";
      }
    }
  3. Then, let's store and retrieve an instance of this class:

    Employee sample = new Employee("Ihab", 26);
    client.set("engineer", 20, sample);
    
    System.out.println((Employee)client.get("engineer"));

The output will be like the following:

2013-10-29 19:22:26.928 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/127.0.0.1:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2013-10-29 19:22:26.935 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl@680e62df
Employee("Ihab", 26)
2013-10-29 19:22:26.964 INFO net.spy.memcached.MemcachedConnection:  Shut down memcached client

How it works...

Basically, we are creating a MemcachedClient object that creates our memcached connection, note that this object is quite smart and does automatic reconnect on connection failure. By default, we are using the plain-text protocol but in the second example we are using the new binary protocol which is far more efficient.

The second snippet also shows how to configure MemcachedClient to connect to multiple memcached servers (cluster), automatic data distribution will be done for you.

The first method we used on the client object is set which is actually asynchronous, this means that it works like fire and forget, it does not block the current thread until the actual set operation happens. Then, we used get which is synchronous (the opposite), it blocks until data is retrieved and returns that data as Object, that's why we need casting to get a reference of the correct object type.

Java has an already very stable data serialization mechanism, and that's exactly what we have used. Standard types are serializable by default but what happens if you are trying to serialize your custom Employee object to memcached? You need to implement the serializable interface for that, then magically everything works as presented in the last recipe.

There's more...

Spymemcached offers an asynchronous API for get as well, it's quite interesting actually and if you are familiar with java.util.concurrent.Future you will find it very easy to follow and understand.

The idea is that client.asyncGet returns a Future<Object> which you can use to retrieve the value asynchronously. You can use this future object to get the actual value later and set a timeout on your get request, as follows:

Future<Object> fobject = client.asyncGet("engineer");
try {
    fobject.get(10, TimeUnit.SECONDS);
} catch (InterruptedException e) {
    e.printStackTrace();
} catch (ExecutionException e) {
    e.printStackTrace();
} catch (TimeoutException e) {
    fobject.cancel(false);
}

What you can see here, is that we tried to get the future and we set 10 seconds for our trial, if the timeout expired, we get a TimeoutException, and then we can safely cancel the operation (by calling cancel() on the future). This means that we are not interested in the operation anymore.

You can also catch multiple exceptions to handle different types of potential failures, such as InterruptedException, which means that something interrupted the background thread, or ExecutionException, which means that an exception was thrown while trying to execute the background job.