一、XMemcached简介
XMemcached是一个新java memcached client。也许你还不知道memcached是什么?可以先看看这里。简单来说,Memcached 是一个高性能的分布式内存对象的key-value缓存系统,用于动态Web应用以减轻数据库负载,现在也有很多人将它作为内存式数据库在使用,memcached通过它的自定义协议与客户端交互,而XMemcached就是它的一个java客户端实现。
二、使用指南
2.1 简单例子
对于用户来说,最主要的功能是存取数据,假设我们有一个memcached节点IP地址或者域名是host,端口是11211,一个简单的存取数据的例子如下:
MemcachedClientBuilder builder = newXMemcachedClientBuilder(
AddrUtil.getAddresses(“localhost:11211”));
MemcachedClient memcachedClient = builder.build();
try {
memcachedClient.set("hello", 0, "Hello,xmemcached");
String value = memcachedClient.get("hello");
System.out.println("hello=" + value);
memcachedClient.delete("hello");
value = memcachedClient.get("hello");
System.out.println("hello=" + value);
} catch (MemcachedException e) {
System.err.println("MemcachedClientoperation fail");
e.printStackTrace();
} catch (TimeoutException e) {
System.err.println("MemcachedClientoperation timeout");
e.printStackTrace();
} catch (InterruptedException e) {
// ignore
}
try {
memcachedClient.shutdown();
} catch (IOException e) {
System.err.println("ShutdownMemcachedClient fail");
e.printStackTrace();
}
因为XMemcachedClient的创建有比较多的可选项,因此提供了一个XMemcachedClientBuilder用于构建MemcachedClient。MemcachedClient是主要接口,操作memcached的主要方法都在这个接口里,XMemcachedClient是它的一个实现。传入的memcached节点列表要求是类似”host1:port1 host2:port2 …”这样的字符串,通过AddrUtil.getAddresses方法获取实际的IP地址列表。存储数据是通过set方法,它有三个参数,第一个是存储的key名称,第二个是expire时间(单位秒),超过这个时间,memcached将这个数据替换出去,0表示永久存储(默认是一个月),第三个参数就是实际存储的数据,可以是任意的java可序列化类型。获取存储的数据是通过get方法,传入key名称即可。如果要删除存储的数据,这是通过delete方法,它也是接受key名称作为参数。XMemcached由于是基于nio,因此通讯过程本身是异步的,client发送一个请求给memcached,你是无法确定memcached什么时候返回这个应答,客户端此时只有等待,因此还有个等待超时的概念在这里。客户端在发送请求后,开始等待应答,如果超过一定时间就认为操作失败,这个等待时间默认是一秒,上面例子展现的3个方法调用的都是默认的超时时间,这三个方法同样有允许传入超时时间的重载方法,例如
Value=client.get(“hello”,3000);
就是等待3秒超时,如果3秒超时就跑出TimeutException,用户需要自己处理这个异常。因为等待是通过调用CountDownLatch.await(timeout)方法,因此用户还需要处理中断异常InterruptException。最后的MemcachedException表示Xmemcached内部发生的异常,如解码编码错误、网络断开等等异常情况。
2.2 CAS操作
Memcached是通过cas协议还实现原子更新,所谓原子更新就是compare and set,原理类似乐观锁,每次请求存储某个数据同时要附带一个cas值,memcached比对这个cas值与当前存储数据的cas值是否相等,如果相等就让新的数据覆盖老的数据,如果不相等就认为更新失败,这在并发环境下特别有用。XMemcached提供了对CAS协议的支持(无论是文本协议还是二进制协议),CAS协议其实是分为两个步骤:获取CAS值和尝试更新,因此一个典型的使用场景如下:
GetsResponse<Integer>result = client.gets("a");
long cas = result.getCas();
if (!client.cas("a", 0, 2, cas)) {
System.err.println("caserror");
}
首先通过gets方法获取一个GetsResponse,此对象包装了存储的数据和cas值,然后通过cas方法尝试原子更新,如果失败打印”cas error”。显然,这样的方式很繁琐,并且如果你想尝试多少次原子更新就需要一个循环来包装这一段代码,因此XMemcached提供了一个CASOpertion接口包装了这部分操作,允许你尝试N次去原子更新某个key存储的数据,无需显式地调用gets获取cas值,上面的代码简化为:
client.cas("a", 0, newCASOperation<Integer>() {
publicint getMaxTries() {
return 1;
}
public Integer getNewValue(long currentCAS, Integer currentValue) {
return 2;
}
});
CASOpertion接口只有两个方法,一个是设置最大尝试次数的getMaxTries方法,这里是尝试一次,如果尝试超过这个次数将抛出一个TimeoutException,如果你想无限尝试,可以将返回值设定为Integer.MAX_VALUE;另一个方法是根据当前获得的GetsResponse来决定更新数据的getNewValue方法,如果更新成功,这个方法返回的值将存储成功,这个方法的两个参数是最新一次gets返回的GetsResponse结果。
2.3 更全面的例子
一些更全面的例子,展现了MemcachedClient接口的主要方法:
MemcachedClientBuilder builder = newXMemcachedClientBuilder(
AddrUtil.getAddresses(“localhost:12000”));
MemcachedClientclient = builder.build();
client.flushAll();
if (!client.set("hello", 0, "world")) {
System.err.println("seterror");
}
if (client.add("hello", 0, "dennis")) {
System.err.println("Adderror,key is existed");
}
if (!client.replace("hello", 0, "dennis")) {
System.err.println("replaceerror");
}
client.append("hello", " good");
client.prepend("hello", "hello");
String name = client.get("hello", newStringTranscoder());
System.out.println(name);
client.deleteWithNoReply(“hello”);
首先存储了hello对应的world字符串,然后调用add和replace方法去尝试添加和替换,因为数据已经存在,因此add会失败,同样replace在数据存在的情况才会成功,也就是将hello对应的数据更新为dennis,然后通过append和prepend方法在dennis前后加上了字符串hello和good,因此通过get返回的结果是hello dennis good。而删除数据则是通过deleteWithNoReply方法,这个方法删除数据并且告诉memcached不用返回应答,因此这个方法不会等待应答直接返回,特别适合于批量处理;同样地,set、add、replace等方法也有相应的withNoReply重载版本,具体请看API文档。
下面这个例子展现了incr/decr操作的使用,两个操作类似java中的原子类如AtomicIntger,用于原子递增或者递减变量数值:
assert(1==this.memcachedClient.incr("a", 5, 1));
assert(6==this.memcachedClient.incr("a", 5));
assert(10==this.memcachedClient.incr("a", 4));
assert(9==this.memcachedClient.decr("a", 1));
assert(7==this.memcachedClient.deccr("a", 2));
incr和decr都有三个参数的方法,第一个参数指定递增的key名称,第二个参数指定递增的幅度大小,第三个参数指定当key不存在的情况下的初始值。两个参数的重载方法省略了第三个参数,默认指定为0。
Memcached提供了统计协议用于查看统计信息:
Map<InetSocketAddress,Map<String,String>>result=client.getStats();
getStats方法返回一个map,其中存储了所有已经连接并且有效的memcached节点返回的统计信息,你也可以统计具体的项目,如统计items项目:
Map<InetSocketAddress,Map<String,String>>result=client.getStatsByItem(“items”);
只要向getStatsByItem传入需要统计的项目名称即可。
MemcachedClientBuilderbuilder = new XmemcachedClientBuilder
(AddrUtil.getAddresses("10.180.44.224:11211zhouxq:11211"),new int[]{1,3});
XMemcached允许通过设置节点的权重来调节memcached的负载,设置的权重越高,该memcached节点存储的数据将越多,所承受的负载越大。
xmemcached的权重是通过复制连接的多个引用来实现的,比如权重为3,那么就复制3个同一个连接的引用放在集合中让MemcachedSessionLocator查找。
改变节点权重,可以通过setServerWeight方法:
public void setServerWeight(String server,int weight);
weight 与servers对应的节点的权重
weight 可以有也可无
weight 值大则权重大,否则小
传入一个int数组,里面的元素就是节点对应的权重值,比如这里设置"10.180.44.224:1121"节点的权重为1,而"zhouxq:11211"的权重为3。
类似的XMemcachedClient()和XMemcachedClientBuilder相同
设置连接池大小
builder.setConnectionPoolSize(5);
与Spring框架集成
通过XMemcachedClientFactoryBean类,即可与spring框架集成
最简单例子
<bean name="memcachedClient" destroy-method="shutdown"
class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean">
<propertyname="servers">
<value>host1:port1host2:port2</value>
</property>
</bean>
然后在bean中就可以使用memcachedClient了
复杂一点儿的例子
<beanname="memcachedClient" destroy-method="shutdown"
class="net.rubyeye.xmemcached.utils.XMemcachedClientFactoryBean">
<property name="servers">
<value>host1:port1host2:port2 host3:port3</value>
</property>
<property name="weights">
<list>
<value>1</value>
<value>2</value>
<value>3</value>
</list>
</property>
<propertyname="sessionLocator">
<beanclass="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator"/>
</property>
<property name="transcoder">
<beanclass="net.rubyeye.xmemcached.transcoders.SerializingTranscoder"/>
</property>
<propertyname="bufferAllocator">
<beanclass="net.rubyeye.xmemcached.buffer.SimpleBufferAllocator">
</property>
</bean>
其中各参数的意义:
参数 | 含义 |
servers | 服务器列表,格式:ip:port |
weights | 主机映射:host1对应1号、host2对应2号.. |
sessionLocator | Session 分配器,有自带的,影响分布式 |
transcoder | 通信编码方式 |
bufferAllocator | 缓冲区分配器 |
转载地址:http://blog.csdn.net/ljhabc1982/article/details/6338898