Membase跟Java入门

Membase和Java入门

介绍

现在你已经安装了Membase并且可能已经创建了Membase服务器集群,现在就可以安装客户端库 spymemcached, 并且开始存储数据了。

下面是本文的纲要:

  1. 下载Java Membase客户端库,spymemcached.

  2. 创建一个功能层,并且将Membase客户端库设置为引用库(referenced library).

  3. 写一个简单的程序演示连接到Membase并且存储数据。

  4. 展示一些简单程序中没有涉及的API方法。

下载Membase客户端库

Couchbase下载客户端库。这是一个你可以用在你的Java环境中的jar文件。

Hello Membase

你可能很好奇,最简单的与Membase通信的Java程序会是什么样,你应该怎么用Java命名行工具编译并且运行它。如果有兴趣请看下面的清单1。

清单1: Main.java

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import net.spy.memcached.AddrUtil;
import net.spy.memcached.MemcachedClient;

public class Main {

    public static void main(String[] args) {

        MemcachedClient client;

        try {
            client = new MemcachedClient(AddrUtil.getAddresses(args[0]));
        } catch (IOException e) {
            e.printStackTrace();
            return;
        }

        Object spoon = client.get("spoon");

        if (spoon == null) {
            System.out.println("There is no spoon.");
            client.set("spoon", 10, "Hello World!");
        } else {
            System.out.println((String)spoon);
        }

        client.waitForQueues(1, TimeUnit.MINUTES);

        System.exit(0);
    }

}
  1. 将清单1中的代码放入一个名为Main.java的文件中。

  2. 将下载的memcached-2.6.jar文件放到同一个目录。

  3. 输入下面的命令:

    $ javac -cp memcached-2.6.jar Main.java
    $ java -cp .;memcached-2.6.jar Main 10.0.0.33:11211

当然,需要使用你自己的Memcache服务器IP地址。如果你在Linux或者MacOS上操作,将第二个命令行中的分号换成冒号。程序将会产生下面的输出:

2011-05-12 22:11:56.281 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/10.0.0.33:11211,
#Rops=0, #Wops=0, #iq=0,
topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2011-05-12 22:11:56.284 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl
@15dfd77
There is no spoon.

这个输出的大部分内容都是客户端库产生的日志,告诉你客户端内部进行到哪一步,可以帮助你分析问题。这儿说的是一个Membase连接已经添加,并且连接状态已经改变。然后代码显示键 spoon 没有在Membase中存在。

在10秒钟之内再次运行这个程序将会产生如下输出:

2011-05-12 22:14:15.800 INFO net.spy.memcached.MemcachedConnection:  Added {QA sa=/10.0.0.33:11211, #Rops=0, #Wops=0, #iq=0,
topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2011-05-12 22:14:15.803 INFO net.spy.memcached.MemcachedConnection:  Connection state changed for sun.nio.ch.SelectionKeyImpl
@15dfd77
Hello World!

你再一次看到日志信息,根据这次的指示,键 spoon 的值“Hello World”在Membase中被找到了。恭喜,你已经在一个更大的世界中迈出了一小步。

Membase API 概述

Membase客户端库有很多API方法,你可以用他们实现你的分布式内存魔力。下面将MemcachedClient方法分为几个类别,为你以后的工作提供一个快速参考。

表1. 同步方法(Synchronous Methods)

decr 减少键并返回值Decrement a key and return the value.
get 从缓存中获得一个特定值Gets a particular value from the cache.
getBulk 同时获得多个值Gets many values at the same time.
gets 获得一个值以及检查和设置支持Gets a particular value with Check And Set support.
incr 增加一个键的值Increment the value of a key.

表 2. 同步检查和设置(Synchronous Check And Set)

cas 执行检查和设置操作Perform a Check And Set operation.

表3. 异步方法(Asynchronous Methods)

add 在缓存中增加一个对象,如果taAdds an object to the cache if it does not exist already.
delete 从缓存中删除一个值Deletes a value from the cache.
flush 将所有服务器上的缓存清空Clears the cache on all servers.

表4.异步检查和设置( Asynchronous Check And Set)

append Append to an existing value in the cache.
asyncCAS Check and set values of particular keys.
asyncDecr Decrement a value.
asyncGet Get a particular value.
asyncGetBulk Get many values at the same time.
asyncGets Get a value with CAS support.
asyncIncr Increment a value.

表5. 状态方法(Status Methods)

addObserver Adds an observer to watch the connection status.
getAvailableServers Returns a list of, shocker, available servers.
getNodeLocator Returns a read only instance of the node locator.
getStats Returns connection statistics.
getTranscoder Returns the default transcoder instance.
getUnavailableServers Returns a list of the servers that are not available.
getVersions Returns the versions of all connected servers.

一个改动较大的程序A More Substantial Program

如果你对改动较大的程序有兴趣,请下载样例代码和Eclipse工程,这样你就可以在Eclipse开发环境中运行了。这个程序会更具用户配置创建多个线程,每个线程都会存入(或者读取)100个随机数。每个线程都会创建一个MemcachedClient对象实例,然后执行gets()操作查找指定的keys。如果键没有被设置,gets()操作就会返回null。这种情况下线程自己会创建值并且设置到Membase中,这样会花费100毫秒去执行。这种情况模拟了一个高昂的数据库操作。你可以在文章末尾找到这个简单程序的完整源代码。

让我们讨论这个程序中的一些细节,这样你可以理解连接Membase服务器,测试已有键值对,设置一个键值的一些基础知识。这些操作将会让你知道如何开始。

清单2. 连接到一系列的Membase服务器:

65:                 MemcachedClient client = new MemcachedClient(
 66:                         AddrUtil.getAddresses(addresses));

从这几行你可以看到你需要创建一个MemcachedClient实例。有很多的方法去创建,不过我认为涉及AddrUtil 类的构造器很重要,这个类可以解析用逗号或者空格分隔的服务器地址和端口列表,例如下面所列:

host-or-ip:port host-or-ip:port

你所连接的端口将会成为MOXI端口,11211是一个有效地代理,它知道集群中的其他所有服务器并且提供快速协议接入。所以这种集群情况下,按照下面格式提供一个地址字符串会很好的进行工作:

String addresses = "10.0.0.33:11211 10.0.0.57:11211";

清单 3 is an abridged excerpt that shows the creation of an IntegerTranscoder, which is a useful class for converting objects in Membase back to integers when needed. This is for convenience and reduces type casting. You can then see a line 82 that a the gets() method is called. This returns a CASValue<T> of type integer which is useful for checking and setting a value. If the value is null it means that membase hasn't been given a value for this key. The code then sets a value. Otherwise, we can get its value and do something with it.

清单 3. 检查和设置操作

67:                 IntegerTranscoder intTranscoder = new IntegerTranscoder();
 68:

 82:                     CASValue<Integer> value = client.gets(key,
 83:                             intTranscoder);
 84:
 85:                     if (value == null) {
 86:                         // The value doesn't exist in Membase
 87:                         client.set(key, 15, rand.nextInt(), intTranscoder);
 88:
 89:                         // Simulate the value taking time to create.
 90:                         Thread.sleep(100);
 91:
 92:                         created++;
 93:
 94:                     } else {
 95:
 99:                         int v = value.getValue();
100:
107:                     }

Setting values in Membase are done asynchronously, and the application does not have to wait for these to be completed. Sometimes, though, you may want to ensure that Membase has been sent some values, and you can do this by calling client.waitForQueues() and giving it a timeout for waiting for this to occur, as shown in Listing 4.

清单4. 等待数据设置进Membase。

109:                     client.waitForQueues(1, TimeUnit.MINUTES);

How to Build and Run the Sample Application

In order to build and run the sample application, you should unzip the attached sample to a directory on your hard drive. The sample application comes with an Eclipse project file and can easily be imported into Eclipse using the following:

  1. Choose File | Import > General > Existing Projects into Workspace.

  2. In the Import Project dialog, click the Browse button next to the Select root directory text field and navigate to where you unzipped the sample application.

  3. Make sure that the GettingStarted project is selected, and hit the Finish button.

You should now have the project imported into your project explorer in Eclipse. Next you will want to run the application.

  1. Right click the GettingStarted project and select Run As | Run Configurations

  2. Double click the "Java Application" node to create a new configuration.

  3. Name this "Membase Client".

  4. Click the "Main" tab.

  5. Click the Search button and choose the com.acme.membase.gettingstarted.Main class to run.

  6. Click the "Arguments" tab.

  7. In the "Program Arguments" tab type something like: "10.0.0.33:11211" 5

  8. Click the "Apply" button.

  9. Click the "Run" button.

Running this program generates the following output the first time:

Client-2 took 37.2500 ms per key. Created 35. Retrieved 65 from cache.
Client-3 took 37.7800 ms per key. Created 35. Retrieved 65 from cache.
Client-4 took 37.7100 ms per key. Created 35. Retrieved 65 from cache.
Client-0 took 37.8300 ms per key. Created 35. Retrieved 65 from cache.
Client-1 took 37.8400 ms per key. Created 35. Retrieved 65 from cache.

Running the program a second time before 15 seconds elapses, produces this output instead:

Client-1 took 4.6700 ms per key. Created 0. Retrieved 100 from cache.
Client-3 took 4.6000 ms per key. Created 0. Retrieved 100 from cache.
Client-4 took 4.7500 ms per key. Created 0. Retrieved 100 from cache.
Client-2 took 4.7900 ms per key. Created 0. Retrieved 100 from cache.
Client-0 took 4.8400 ms per key. Created 0. Retrieved 100 from cache.

There are a few things that are interesting about the output. In the first scenario, the five threads collaborate to produce the sequence of random numbers such that the average time per key is significantly less than 100ms. Each thread is creating 35 numbers, but reading 65 from the cache.

In the second run, because the 15 second timeout has not elapsed yet, all of the random numbers were retrieved from the cache by all of the threads. Notice that reading these values from Membase only takes a few milliseconds.

Conclusion

You now know how to obtain the Membase Java client library, and write small Java programs to connect with your Membase cluster and interact with it. Congratulations, you will be able to save your servers from burning down, and impress your users with the blazing fast response that your application will be able to achieve.