Membase 是一个NOSQL数据库。它被设计为在MEMCACHED(一个流行的内存缓存工具)之后的一个持久化存储。Membase相对比较新但是已经在高性能NOSQL世界有了一个扎实的落脚点。
本文是一个通过Java使用Membase数据库的快速教程。
安装MEMBASE
参考Membase.org的说明
客户端
与Membase的交互类似与Memcached的交互。我们将会使用SpyMemcached Java 客户端。请从 这儿下载。
代码
本项目中所有用到的代码都提供在GitHub : https://github.com/sujee/membase-tutorial
这一个elipse工程,并且已经可以运行。
让我们开始
这儿的JAVA代码-它将一串key,value写入Membase并且再将他们读取出来。
与Membase的交互类似与Memcached的交互。我们将会使用SpyMemcached Java 客户端。请从 这儿下载。
代码
本项目中所有用到的代码都提供在GitHub : https://github.com/sujee/membase-tutorial
这一个elipse工程,并且已经可以运行。
让我们开始
这儿的JAVA代码-它将一串key,value写入Membase并且再将他们读取出来。
这儿的JAVA代码-它将一串key,value写入Membase并且再将他们读取出来。
// MembaseTest1 package tutorial;import java.net.InetSocketAddress;import net.spy.memcached.MemcachedClient;/*** Write / Read from Membase* * @author sujee**/public class MembaseTest1{ static int MAX = 100; static String server = “localhost”; static int port = 11211; public static void main(String[] args) throws Exception { MemcachedClient cache = new MemcachedClient(new InetSocketAddress(server, port)); cache.flush(); // 清除所有 long t1 = System.currentTimeMillis(); for (int i = 0; i < MAX; i++) { String s = new Integer(i).toString(); // key : integer converted to String (keys are always string) // time to live : in seconds, 3600 seconds (1h), 0 means no expiration // value : actual integer. This can be an object. Our integer will be converted to ‘Integer’ // class by ‘auto boxing’ proess Object o = cache.set(s, 0, i); System.out.println(“cache put : “ + s + ” : “ + i + “, result “ + o); } long t2 = System.currentTimeMillis(); System.out.println(“Time for “ + MAX + ” puts is “ + (t2 – t1) + ” ms”); t1 = System.currentTimeMillis(); int nulls = 0; for (int i = 0; i < MAX; i++) { String s = new Integer(i).toString(); Object o = cache.get(s); System.out.println(“Cache get : “ + s + ” : “ + o); if (o == null) nulls++; } t2 = System.currentTimeMillis(); cache.shutdown(); System.out.println(“Time for “ + MAX + ” gets is “ + (t2 – t1) + ” ms. nulls “ + nulls); }} 你可以在eclipse中运行这个文件(MembaseTest1)。或者从命令行执行
sh compile.sh sh run.sh or java -cp classes/:lib/memcached-2.5.jar tutorial.MembaseTest1Membase运行在本地,端口为11211(默认的memcached端口)
我们在一开始就清洗了整个数据集,这样我们就可以有个干净的初始环境。
Setcache.set (string_key, expiration_time, object_value)
我们的键是一串字符型的数字,我们的对象是是整数型对象。
下面是输出样例:
2010-11-29 23:36:33.234 INFO net.spy.memcached.MemcachedConnection: Added {QA sa=localhost/127.0.0.1:11211, #Rops=0, #Wops=0, #iq=0, topRop=null, topWop=null, toWrite=0, interested=0} to connect queue
2010-11-29 23:36:33.240 INFO net.spy.memcached.MemcachedConnection: Connection state changed for sun.nio.ch.SelectionKeyImpl@b34bed0
cache put : 0 : 0, result net.spy.memcached.internal.OperationFuture@578088c0
cache put : 1 : 1, result net.spy.memcached.internal.OperationFuture@37922221
cache put : 2 : 2, result net.spy.memcached.internal.OperationFuture@5afec107
cache put : 3 : 3, result net.spy.memcached.internal.OperationFuture@b32e13d
cache put : 4 : 4, result net.spy.memcached.internal.OperationFuture@39617189
cache put : 5 : 5, result net.spy.memcached.internal.OperationFuture@2c64f6cd
…
…
Spy Memcache 客户端缓存了很多操作,这样可以提升性能。你可以看到cache.set方法返回了一个 ‘OperartionFuture’ 对象。key-value最终将会在Membase中持久化。
Get现在我们试着看看我们刚写的读取语句。 我们用了同样的客户端。输出结果就像下面所示:
Cache get : 96 : 96
Cache get : 97 : 97
Cache get : 98 : 98
Cache get : 99 : 99
Time for 100 gets is 77 ms. nulls 0
我们密切注意NULL值。我们这次不应该获得NULL,如我们所希望的null个数为0。
代码也记录了时间戳,我们可以看到操作是多么得快。
模拟多个客户端
在上面的例子中我们从同一个客户端进行读写。但在实际场景中,多个客户端都会对Membase进行读写。现在我们用两个不同的客户端连接模拟这种情况。
在这个版本中,我们使用一个连接进行写操作另一个连接进行读操作。
// MembaseTest2package tutorial; import java.net.InetSocketAddress;import net.spy.memcached.MemcachedClient; /*** simulates writing / reading from two different clients*/public class MembaseTest2{ static int MAX = 1000; static String server = “localhost”; static int port = 11211; public static void main(String[] args) throws Exception { MemcachedClient cache = new MemcachedClient(new InetSocketAddress(server, port)); cache.flush(); // clear all long t1 = System.currentTimeMillis(); for (int i = 0; i < MAX; i++) { String s = new Integer(i).toString(); // key : integer converted to String (keys are always string) // time to live : in seconds, 3600 seconds (1h), 0 means no expiration // value : actual integer. This can be an object. Our integer will be converted to ‘Integer’ // class by ‘auto boxing’ proess Object o = cache.set(s, 0, i); System.out.println(“cache put : “ + s + ” : “ + i + “, result “ + o); } long t2 = System.currentTimeMillis(); cache.shutdown(); // close the client System.out.println(“Time for “ + MAX + ” puts is “ + (t2 – t1) + ” ms”); // open another connection cache = new MemcachedClient(new InetSocketAddress(server, port)); t1 = System.currentTimeMillis(); int nulls = 0; for (int i = 0; i < MAX; i++) { String s = new Integer(i).toString(); Object o = cache.get(s); System.out.println(“Cache get : “ + s + ” : “ + o); if (o == null) nulls++; } t2 = System.currentTimeMillis(); cache.shutdown(); System.out.println(“Time for “ + MAX + ” gets is “ + (t2 – t1) + ” ms. nulls “ + nulls + “\n”); }}java -cp classes/:lib/memcached-2.5.jar tutorial.MembaseTest2
Cache get : 0 : 0
Cache get : 1 : 1
…….
…..
Cache get : 997 : null
Cache get : 998 : null
Cache get : 999 : null
Time for 1000 gets is 540 ms. nulls 42
现在就能看到一个情况,当我们读取刚刚设置的值的时候,就会有NULL产生的情况了。
那么这儿到底发生了些什么了?
请记住,Spy Memcache客户端为了提高性能缓存了不少操作。当我们调用“shutdown”的时候客户端没有把所有的缓存值写入数据库就退出了。所以这些键值就很简单的丢失了。
让我们修正这个问题。
当我们做完SET操作, 让我们更优雅的关闭这个客户端。我们给他10秒的时间再退出。希望这样可以让客户端有机会把所有的缓存操作都执行完成。
……long t2 = System.currentTimeMillis();cache.shutdown(10, TimeUnit.SECONDS); // graceful shutdownSystem.out.println(“Time for “ + MAX + ” puts is “ + (t2 – t1) + ” ms”); // open another connectioncache = new MemcachedClient(new InetSocketAddress(server, port));……
java -cp classes/:lib/memcached-2.5.jar tutorial.MembaseTest3
output:
…
…
Cache get : 998 : 998
Cache get : 999 : 999
Time for 1000 gets is 500 ms. nulls 0
没有任何NULL值。我们获得了所有写入的值。
所以现在我们很成功的模拟了多个客户端的情况。有一件事情需要记住,客户端做了缓存所以需要优雅的关闭它保证没有数据丢失。