Memcached is a general purpose memory caching system used in many websites. It stores values in key-value pair of (String-Object). The Object can be a result of a database call, API or page rendering. The memcahced wiki describes it best. In this article, we explore a practical application of memcached. The following are the prerequisites:
- A memcached server
- A memcached java API. I would be using spymemcached.
I have an ubuntu virtual box, where I will install memcached server. The basic steps of a running installation of memcached are:
Step 1: apt-get install memcached
Step 2: memcached -u root -d -m 24 -l 127.0.0.1 -p 11211
where:
-p=port number of memcached
-m 24=size of data allocated
Once memcached is up and running, set your java environment with spymemcached jar. Memcached is capable of supporting multiple disconnected servers, but we shall use only one as an example in this code. There are few things we should be clear about memcached:
- Memcached is, by default, a Least Recently Used cache. It is designed to have items expire after a specified amount of time.
- Items are made up of a key, an expiration time, optional flags, and raw data.
- Old items are also deleted if the server runs out of memory.
We start with creating a sample connection manager class with a connection to memcached server:
package in.brainfry.memcache;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.concurrent.Future;
import net.spy.memcached.MemcachedClient;
public class MemClient {
private static MemcachedClient client = null;
static {
try {
client = new MemcachedClient(new InetSocketAddress("10.0.0.7",
11211));
System.out.println("CONNECTED TO SERVER");
} catch (IOException e) {
e.printStackTrace();
System.exit(-1);
}
}
public Future<Boolean> addToMemCache(String key, int timeOut, Object val) {
Future<Boolean> future = client.set(key, timeOut, val);
return future;
}
public Object getMemcachedValue(String key) {
return client.get(key);
}
} Notice how the connection is maintained and not created and closed every time we add or get a value. This is important for the speed up application by avoiding multiple connection close/open. In a heavy loaded scenario, this becomes very important, and so it may be necessary to maintain multiple connections to the server by creating multiple MemcachedClient objects.
Once the client for the connection pool is done, we create a sample code which uses the above class to store values and retrieve them from memcached. In this sample program, we perform a 3-step operation. First, we fill memcached with a random 100 key-value pairs. Second, we read the values to see if they were properly inserted. We take a break so that the cutoff time is reached. Then we read again to see if the values remain.
Before running the below program, make sure that you have opened the firewall on port 11211 on the server. Also, open /etc/memcached.conf and search for -l 127.0.0.1 and replace it with -l 0.0.0.0 if you are connecting from a different machine.
package in.brainfry.memcache;
import java.util.ArrayList;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.logging.Level;
import java.util.logging.Logger;
public class MemClientUser {
private static ArrayList<String> keyStore = new ArrayList<String>();
private static ArrayList<Future<Boolean>> futures = new ArrayList<Future<Boolean>>();
private static int counter = 0;
public static void main(String[] args) throws InterruptedException,
ExecutionException {
Logger.getLogger("net.spy.memcached").setLevel(Level.SEVERE);
final MemClient memClient = new MemClient();
for (int i = 0; i < 100; i++) {
final String key = getRandomKey();
final String value = getValueFromASource();
keyStore.add(key);
Future<Boolean> future = memClient.addToMemCache(key, 60, value);
try {
future.get();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
if (future != null) {
futures.add(future);
counter++;
} else
System.out.println("future is null??");
}
System.out.println("VALUES TRIED: " + counter);
counter = 0;
for (final String key : keyStore) {
String val = (String) memClient.getMemcachedValue(key);
if (val != null)
counter++;
}
System.out.println("VALUES FOUND: " + counter);
// This ensures the the values are expired
Thread.sleep(60000);
counter = 0;
for (final String key : keyStore) {
String val = (String) memClient.getMemcachedValue(key);
if (val != null)
counter++;
}
System.out.println("VALUES REMAINING: " + counter);
}
private static String getRandomKey() {
return "RANDOM_KEY" + new Random().nextInt(99999);
}
private static String getValueFromASource() {
// This function ideally would return a value from a database, or an API
// call
return "RANDOM_VALUE" + new Random().nextInt(99999);
}
} Running the above program yeilds:
CONNECTED TO SERVER VALUES TRIED: 100 VALUES FOUND: 100 VALUES REMAINING: 0
I am new to membase and i tried to run above Program I struck with error Can u please help me on this.
Error Log :
Exception in thread “main” java.lang.NullPointerException
at com.acme.membase.gettingstarted.MemClient.addToMemCache(MemClient.java:29)
at com.acme.membase.gettingstarted.MemClientUser.main(MemClientUser.java:33)
Please help me on this…..