Getting_Started_zh
簡單介紹
依賴包
簡單例子
設置權重
使用二進制協議
使用Kestrel
動態增刪節點
Nio連接池
使用CAS原子更新
簡單介紹
Xmemcached支持memcached所有的二進制協議(從1.2.0開始)和文本協議,并且支持對Kestrel(一個scala寫的MQ)的兼容訪問。 更多信息請參考用戶指南
依賴包
Xmemcached 1.x 需要依賴common-logging和yanf4j-0.70http://code.google.com/p/yanf4j/downloads/list)
Xmemcached 1.2.0-stable開始及以后版本需要依賴slf4j(http://www.slf4j.org/)和yanf4j-1.0.1
memcached 1.2.0 and 1.2.1 依賴 yanf4j 1.0.1
memcached 1.2.2 依賴 yanf4j 1.1.0
memcached 1.2.3 and 1.2.4 依賴 yanf4j 1.1.1
Xmemcached 1.2.5 不再依賴yanf4j
如果您使用maven構建,只需要添加依賴即可使用xmemcached:
com.googlecode.xmemcached xmemcached 1.2.5
簡單例子
MemcachedClient client=new XMemcachedClient("host",11211);
//同步存儲value到memcached
client.set("key",3600,someObject);
//從memcached獲取key對應的value
Object someObject=client.get("key");
//從memcached獲取key對應的value,操作超時2秒
someObject=client.get("key",2000);
//刪除value
client.delete("key");
設置權重
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000 localhost:12001"),new int[]{1,3});
MemcachedClient memcachedClient=builder.build();
上面的例子將"localhost:12000"節點的權重設置為1,而將"localhost:12001"節點的權重設置為3.當然,你也可以通過JMX調用MBean動態修改權重:
public interface XMemcachedClientMBean{
....
/**
* Set a memcached server's weight
*
* @param server
* @param weight
*/
public void setServerWeight(String server, int weight);
}
使用二進制協議
Xmemcached默認使用成熟的文本協議,memcached 1.4.0正式支持啟用二進制協議,如果你想使用二進制協議,你只要添加一行代碼,設置BinaryCommandFactory即可:
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000 localhost:12001"),new int[]{1,3});
builder.setCommandFactory(new BinaryCommandFactory());//use binary protocol
MemcachedClient memcachedClient=builder.build();
使用Kestrel
Kestrel是twitter開源的一個scala寫的簡單高效MQ,它支持memcached文本協議,但是并不完全兼容,例如它不支持flag,導致很多利用flag做序列化的客戶端無法正常運作。因此Xmemcached特意提供了KestrelCommandFactory用于支持Kestrel。使用KestrelCommandFactory即可擁有如下好處:
默認關閉get優化,因為kestrel不支持bulk get;
支持kestrel的阻塞獲取和可靠獲取;
允許向kestrel存儲任意java序列化類型。設置KestrelCommandFactory:
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000 localhost:12001"),new int[]{1,3});
builder.setCommandFactory(new KestrelCommandFactory());
MemcachedClient memcachedClient=builder.build();
關于最后一點需要補充說明,由于kestrel不支持flag,因此xmemcached在存儲的數據之前加了4個字節的flag,如果你的全部應用都使用xmemcached,那么沒有問題,如果使用其他clients,會有兼容性的問題,因此Xmemcached還允許關閉這個功能,通過
client.setPrimitiveAsString(true);
設置為true后,原生類型都將存儲為字符串,而序列化類型將無法存儲了。
動態增刪節點
你可以通過編程或者JMX來動態增加或者移除memcached節點:
MemcachedClient client=new XMemcachedClient(AddrUtil.getAddresses("server1:11211 server2:11211"));
//Add two new memcached nodes
client.addServer("server3:11211 server4:11211");
//Remove memcached servers
client.removeServer("server1:11211 server2:11211");
Nio連接池
Xmemcached是基于java nio的client實現,默認對一個memcached節點只有一個連接,這在通常情況下已經有非常優異的表現。但是在典型的高并發環境下,nio的單連接也會遇到性能瓶頸。因此XMemcached支持設置nio的連接池,允許建立多個連接到同一個memcached節點,但是請注意,這些連接之間是不同步的,因此你的應用需要自己保證數據更新的同步,啟用連接池可以通過下面代碼:
MemcachedClientBuilder builder = new XMemcachedClientBuilder(AddrUtil.getAddresses("localhost:12000"));
builder.setConnectionPoolSize(5);
使用CAS原子更新
典型的CAS操作需要先通過gets得到cas值,然后進行cas替換,用起來相當麻煩。XMemcached提供了CASOperation封裝了這兩個操作,提供給用戶統一的使用接口,并且允許設置最多重試次數。詳見下面的例子,啟動N個線程原子更新同一個key的value。
class CASThread extends Thread {
static final class IncrmentOperation implements CASOperation {
/*
*Max repeat times.if repeat times is great than this value,
*xmemcached will throw a TimeoutException.
*/
@Override
public int getMaxTries() {
return Integer.MAX_VALUE;
}
//increase current value
@Override
public Integer getNewValue(long currentCAS, Integer currentValue) {
return currentValue + 1; // 當前值+1
}
}
private XMemcachedClient mc;
private CountDownLatch cd;
public CASThread(XMemcachedClient mc, CountDownLatch cdl) {
super();
this.mc = mc;
this.cd = cdl;
}
public void run() {
try {
//do the cas operation
if (mc.cas("a", 0, new IncrmentOperation()))
this.cd.countDown();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class CASTest {
public static void main(String[] args) throws Exception {
if (args.length < 2) {
System.err.println("Usage:java CASTest [threadNum] [server]");
System.exit(1);
}
//threads num
int NUM = Integer.parseInt(args[0]);
XMemcachedClient mc = new XMemcachedClient(AddrUtil.getAddresses(args[1]));
//initial value is 0
mc.set("a", 0, 0);
CountDownLatch cdl = new CountDownLatch(NUM);
long start = System.currentTimeMillis();
//start NUM threads to increment the value
for (int i = 0; i < NUM; i++)
new CASThread(mc, cdl).start();
cdl.await();
System.out.println("test cas,timed:"
+ (System.currentTimeMillis() - start));
System.out.println("result=" + mc.get("a"));
mc.shutdown();
}
}