Membase 是一个NOSQL数据库。它被设计为在MEMCACHED(一个流行的内存缓存工具)之后的一个持久化存储。Membase相对比较新但是已经在高性能NOSQL世界有了一个扎实的落脚点。
本文是一个通过JAVA使用Membase数据库的快速教程。
参考 Membase.org的说明
与Membase的交互类似与Memcached的交互。我们将会使用SpyMemcached Java 客户端。请从 这儿下载。
本项目中所有用到的代码都提供在GitHub : https://github.com/sujee/membase-tutorial
这一个elipse工程,并且已经可以运行。
这儿的JAVA代码-它将一串key,value写入Membase并且再将他们读取出来。
我们在一开始就清洗了整个数据集,这样我们就可以有个干净的初始环境。
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中持久化。
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
在上面的例子中我们从同一个客户端进行读写。但在实际场景中,多个客户端都会对Membase进行读写。现在我们用两个不同的客户端连接模拟这种情况。
在这个版本中,我们使用一个连接进行写操作另一个连接进行读操作。
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秒的时间再退出。希望这样可以让客户端有机会把所有的缓存操作都执行完成。
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值。我们获得了所有写入的值。
所以现在我们很成功的模拟了多个客户端的情况。有一件事情需要记住,客户端做了缓存所以需要优雅的关闭它保证没有数据丢失。
本文是一个通过JAVA使用Membase数据库的快速教程。
安装MEMBASE
参考 Membase.org的说明
客户端
与Membase的交互类似与Memcached的交互。我们将会使用SpyMemcached Java 客户端。请从 这儿下载。
代码
本项目中所有用到的代码都提供在GitHub : https://github.com/sujee/membase-tutorial
这一个elipse工程,并且已经可以运行。
让我们开始
这儿的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端口)
我们在一开始就清洗了整个数据集,这样我们就可以有个干净的初始环境。
Set
cache.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进行读写。现在我们用两个不同的客户端连接模拟这种情况。
在这个版本中,我们使用一个连接进行写操作另一个连接进行读操作。
// MembaseTest2
package
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"
);
}
}
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 shutdown
System
.
out
.
println
(
"Time for "
+
MAX
+
" puts is "
+
(
t2
-
t1
)
+
" ms"
);
// open another connection
cache
=
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值。我们获得了所有写入的值。
所以现在我们很成功的模拟了多个客户端的情况。有一件事情需要记住,客户端做了缓存所以需要优雅的关闭它保证没有数据丢失。