memcached 命令: http://donald-draper.iteye.com/blog/2395628
memcache Java客户端有三种方式具体介绍可以参见下面这篇文章:
Memcache的三种Java客户端的对比和选择: http://blog.csdn.net/heiyueya/article/details/64441901
三种方式分别为:
1.官方提供的基于传统阻塞io由Greg Whalin维护的客户端memcached client for java
网址: http://www.whalin.com/memcached
特点: 较早推出的memcached JAVA客户端API,应用广泛,运行比较稳定,使用阻塞IO,不支持CAS操作。
github: https://github.com/gwhalin/Memcached-Java-Client
2.Dustin Sallings实现的基于java nio的Spymemcached
网址: http://code.google.com/p/spymemcached/
最新版本:memcached-2.1.jar
特点: A simple, asynchronous, single-threaded memcached client written in java.
用到了java1.5版本的concurrent和nio,存取速度会高于前者,但是稳定性不好,测试中常报timeOut等相关异常,支持CAS操作。
github: https://github.com/dustin/java-memcached-client
3.XMemcached
XMemcached同样是基于Java NIO的客户端,Java NIO相比于传统阻塞IO模型来说,
有效率高(特别在高并发下)和资源耗费相对较少的优点。传统阻塞IO为了提高效率,
需要创建一定数量的连接形成连接池,而NIO仅需要一个连接即可(当然,NIO也是可以做池化处理),相对来说减少了线程创建和切换的开销,这一点在高并发下特别明显。
因此 XMemcached与Spymemcached在性能都非常优秀,在某些方面(存储的数据比较小的情况下)Xmemcached比
Spymemcached的表现更为优秀。
github: https://github.com/killme2008/xmemcached
我们选择XMemcached来实现Memcache的客户端:
本文的源代码可以从以下地址load:
https://github.com/Donaldhan/memcached-demo
启动memcached:
[memcached@donald ~]$ memcached -p 11211 -d -u memcached -l 192.168.126.128 -c 1024 [memcached@donald ~]$ ps -ef | grep memcached root 4514 1248 0 22:01 ? 00:00:00 sshd: memcached [priv] memcach+ 4517 4514 0 22:01 ? 00:00:00 sshd: memcached@pts/1 memcach+ 5172 1 0 22:04 ? 00:00:00 memcached -p 11211 -d -u memcached -l 192.168.126.128 -c 1024 memcach+ 5238 4522 0 22:07 pts/1 00:00:00 grep --color=auto memcached [memcached@donald ~]$
创建memcache属性文件memcached.properties:
############################ ##memcached server ip address list ############standby############## standbyServerList=192.168.126.128:11211 poolName=sidsock poolSize=16
创建属性文件工具类:
package util; import java.io.IOException; import java.io.InputStream; import java.util.Properties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author donald * 2017年9月29日 * 下午10:21:34 */ public class PropertiesUtil { private static final Logger log = LoggerFactory.getLogger(PropertiesUtil.class); private static final String MEMCACHED_CONFIG_FILE = "memcached.properties"; private static volatile PropertiesUtil instance = null; private static Properties properties = null; static{ if (properties == null) { properties = new Properties(); } try { InputStream inputStream = Thread.currentThread().getContextClassLoader() .getResourceAsStream(MEMCACHED_CONFIG_FILE); properties.load(inputStream); } catch (IOException e1) { e1.printStackTrace(); } } /** * * @return */ public static synchronized PropertiesUtil getInstance() { if (instance == null) { instance = new PropertiesUtil(); } return instance; } /** * * @param key * @return */ public String getProperty(String key) { return properties.getProperty(key); } /** * 获取属性int值 * @param key * @return */ public Integer getInteger(String key) { String value = properties.getProperty(key); return Integer.valueOf(value); } public static void main(String[] args) { log.info("serverList:"+PropertiesUtil.getInstance().getProperty("standbyServerList")); } }
创建memcache客户端:
package bootstrap; import java.io.IOException; import java.net.InetSocketAddress; import java.util.List; import java.util.concurrent.TimeoutException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.rubyeye.xmemcached.Counter; import net.rubyeye.xmemcached.GetsResponse; import net.rubyeye.xmemcached.MemcachedClient; import net.rubyeye.xmemcached.MemcachedClientBuilder; import net.rubyeye.xmemcached.XMemcachedClientBuilder; import net.rubyeye.xmemcached.exception.MemcachedException; import net.rubyeye.xmemcached.utils.AddrUtil; import util.PropertiesUtil; /** * Memcached Standby模式 客户端 * @author donald * 2017年10月10日 * 下午12:49:45 */ public class MemcachedStandbyClient { private static final Logger log = LoggerFactory.getLogger(MemcachedStandbyClient.class); private static final String MEMCACHED_SERVER_LIST = "standbyServerList"; private static final String MEMCACHED_POOL_SIZE = "poolSize"; private static PropertiesUtil propertiesUtil = PropertiesUtil.getInstance(); private static volatile MemcachedStandbyClient instance; private static MemcachedClientBuilder builder; private static MemcachedClient memcachedClient; static{ String standbyServerList = propertiesUtil.getProperty(MEMCACHED_SERVER_LIST); ListserverAddresses = AddrUtil.getAddresses(standbyServerList); builder = new XMemcachedClientBuilder(serverAddresses); /** * Xmemcached是基于java nio的client实现,默认对一个memcached节点只有一个连接, * 这在通常情况下已经有非常优异的表现。但是在典型的高并发环境下,nio的单连接也会遇到性能瓶颈。 * 因此XMemcached支持设置nio的连接池,允许建立多个连接到同一个memcached节点, * 但是请注意,这些连接之间是不同步的,因此你的应用需要自己保证数据更新的同步,启用连接池可以通过下面代码: */ /*int poolSize = propertiesUtil.getInteger(MEMCACHED_POOL_SIZE); builder.setConnectionPoolSize(poolSize); */ try { memcachedClient = builder.build(); } catch (IOException e) { log.error("连接异常"); e.printStackTrace(); } } public static synchronized MemcachedStandbyClient getInstance() { if (instance == null) { instance = new MemcachedStandbyClient(); } return instance; } /** * * @param key * @param value * @return */ public boolean set(String key,Object value){ return set(key, 0, value); } /** * * @param key * @param expire 过期时间秒 * @param value * @return */ public boolean set(String key,int expire,Object value){ boolean finish = false; try { finish = memcachedClient.set(key, expire, value); } catch (TimeoutException e) { log.error("set超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("set中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("set错误"); e.printStackTrace(); } return finish; } /** * * @param key * @param value * @return */ public boolean add(String key,Object value){ return add(key, 0, value); } /** * * @param key * @param expire 过期时间秒 * @param value * @return */ public boolean add(String key,int expire,Object value){ boolean finish = false; try { finish = memcachedClient.add(key, expire, value); } catch (TimeoutException e) { log.error("add超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("add中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("add错误"); e.printStackTrace(); } return finish; } /** * * @param key * @return */ public Object get(String key){ Object value = null; try { value = memcachedClient.get(key); } catch (TimeoutException e) { log.error("get超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("get中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("get操作错误"); e.printStackTrace(); } return value; } /** * * @param key * @param appendValue * @return */ public boolean append(String key,Object appendValue){ boolean finish = false; try { finish = memcachedClient.append(key, appendValue); } catch (TimeoutException e) { log.error("append超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("append中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("append操作错误"); e.printStackTrace(); } return finish; } /** * * @param key * @param prependValue * @return */ public boolean prepend(String key,Object prependValue){ boolean finish = false; try { finish = memcachedClient.prepend(key, prependValue); } catch (TimeoutException e) { log.error("prepend超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("prepend中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("prepend操作错误"); e.printStackTrace(); } return finish; } /** * * @param key * @param value * @return */ public boolean replace(String key,Object value){ return replace(key, 0, value); } /** * * @param key * @param expire 过期时间秒 * @param value * @return */ public boolean replace(String key,int expire,Object value){ boolean finish = false; try { finish = memcachedClient.replace(key, expire, value); } catch (TimeoutException e) { log.error("replace超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("replace中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("replace错误"); e.printStackTrace(); } return finish; } /** * * @param key * @param expire * @return */ public boolean touch(String key,int expire){ boolean finish = false; try { finish = memcachedClient.touch(key, expire); } catch (TimeoutException e) { log.error("touch超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("touch中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("touch操作错误"); e.printStackTrace(); } return finish; } /** * @param key * @param step * @param defalut * @return */ public long incr(String key,long step,long defalut){ long value = 0; try { value = memcachedClient.incr(key, step, defalut); } catch (TimeoutException e) { log.error("incr超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("incr中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("incr操作错误"); e.printStackTrace(); } return value; } /** * * @param key * @param step * @return */ public long incr(String key,long step){ long value = 0; try { value = memcachedClient.incr(key, step); } catch (TimeoutException e) { log.error("incr超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("incr中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("incr操作错误"); e.printStackTrace(); } return value; } /** * * @param key * @param step * @return */ public long decr(String key,long step){ long value = 0; try { value = memcachedClient.decr(key, step); } catch (TimeoutException e) { log.error("decr超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("decr中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("decr操作错误"); e.printStackTrace(); } return value; } /** * * @param key * @return */ public long gets(String key){ long sid = 0; try { GetsResponse result = memcachedClient.gets(key); sid = result.getCas(); } catch (TimeoutException e) { log.error("gets超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("gets中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("gets操作错误"); e.printStackTrace(); } return sid; } /** * * @param key * @param obj * @return */ public boolean cas(String key,Object obj){ boolean finish = false; long sid = gets(key); finish = cas(key, 0, obj, sid); return finish; } /** * * @param key * @param expire * @param obj * @param sid key当前版本id * @return */ public boolean cas(String key, int expire, Object obj, long sid){ boolean finish = false; try { finish = memcachedClient.cas(key, expire, obj, sid); } catch (TimeoutException e) { log.error("cas超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("cas中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("cas操作错误"); e.printStackTrace(); } return finish; } /** * @param key * @return */ public boolean delete(String key){ boolean finish = false; try { finish = memcachedClient.delete(key); } catch (TimeoutException e) { log.error("delete超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("delete中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("delete操作错误"); e.printStackTrace(); } return finish; } /** * * @param key * @return */ public void deleteWithNoReply(String key){ try { memcachedClient.deleteWithNoReply(key); } catch (InterruptedException e) { log.error("deleteWithNoReply中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("deleteWithNoReply操作错误"); e.printStackTrace(); } } /** * @param key * @return */ public Counter getCounter(String key) { return getCounter(key,0); } /** * @param key * @param init * @return */ public Counter getCounter(String key,int init) { Counter counter = memcachedClient.getCounter(key,init); return counter; } /** * */ public void flushAll(){ try { memcachedClient.flushAll(); } catch (TimeoutException e) { log.error("flushAll超时"); e.printStackTrace(); } catch (InterruptedException e) { log.error("flushAll中断异常"); e.printStackTrace(); } catch (MemcachedException e) { log.error("flushAll操作错误"); e.printStackTrace(); } } public void shutdown(){ try { memcachedClient.shutdown(); } catch (IOException e) { log.error("客户端关闭异常"); e.printStackTrace(); } } /* (non-Javadoc) * @see java.lang.Object#finalize() */ @Override protected void finalize() { try { memcachedClient.shutdown(); } catch (IOException e) { log.error("memcached 关闭客户端连接失败!"); e.printStackTrace(); } } }
创建测试类:
package bootstrap; import java.util.concurrent.TimeoutException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import net.rubyeye.xmemcached.Counter; import net.rubyeye.xmemcached.exception.MemcachedException; /** * Memcached Standby模式 客户端测试类 * @author * donald * 2017年10月10日 * 下午12:49:45 */ public class MemcachedStandbyClientTest { private static final Logger log = LoggerFactory.getLogger(MemcachedStandbyClientTest.class); public static void main(String[] args) { MemcachedStandbyClient memcachedClient = MemcachedStandbyClient.getInstance(); memcachedClient.set("name", 0, "donald"); String value = (String) memcachedClient.get("name"); log.info("set name={}", value); memcachedClient.delete("name"); value = (String) memcachedClient.get("name"); log.info("delete name={}", value); if (!memcachedClient.set("name", 0, "jamel")) { log.error("set error"); } value = (String) memcachedClient.get("name"); log.info("set name={}", value); if (memcachedClient.add("name", 0, "donald")) { log.error("Add error,key is existed"); } value = (String) memcachedClient.get("name"); log.info("name={}", value); if (!memcachedClient.replace("name", 0, "rain")) { log.error("replace error"); } value = (String) memcachedClient.get("name"); log.info("repalce name={}", value); memcachedClient.append("name", "-han"); value = (String) memcachedClient.get("name"); log.info("append name={}", value); memcachedClient.prepend("name", "0-"); value = (String) memcachedClient.get("name"); log.info("prepend name={}", value); memcachedClient.touch("name", 3); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } value = (String) memcachedClient.get("name"); log.info("after touch name={}", value); memcachedClient.deleteWithNoReply("name"); memcachedClient.set("age", 0, "27"); log.info("age={}", memcachedClient.get("age")); memcachedClient.incr("age", 2, 1);// age 增加2,age不存在,则为1 memcachedClient.incr("age", 1); log.info("incr age={}", memcachedClient.get("age")); memcachedClient.decr("age", 2); log.info("decr age={}", memcachedClient.get("age")); if (!memcachedClient.cas("age", 27)) { log.error("cas error"); } log.info("cas age={}", memcachedClient.get("age")); Counter counter = memcachedClient.getCounter("counter", 0); try { log.info("incrementAndGet counter,{}", counter.incrementAndGet()); log.info("decrementAndGet counter,{}", counter.decrementAndGet()); log.info("addAndGet counter,{}", counter.addAndGet(3)); } catch (MemcachedException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } memcachedClient.flushAll(); memcachedClient.shutdown(); } }
运行测试类,控制台输出如下:
22:20:09.815 [main] INFO net.rubyeye.xmemcached.XMemcachedClient 729- XMemcachedClient is using Text protocol 22:20:09.859 [main] INFO com.google.code.yanf4j.nio.impl.SelectorManager 37- Creating 4 reactors... 22:20:09.876 [main] INFO com.google.code.yanf4j.core.impl.AbstractController 377- The Controller started at localhost/127.0.0.1:0 ... 22:20:18.928 [Xmemcached-Reactor-0] INFO com.google.code.yanf4j.core.impl.AbstractController 253- Add a session: 192.168.126.128:11211 22:20:18.963 [main] INFO bootstrap.MemcachedStandbyClientTest 24- set name=donald 22:20:18.973 [main] INFO bootstrap.MemcachedStandbyClientTest 27- delete name=null 22:20:18.978 [main] INFO bootstrap.MemcachedStandbyClientTest 32- set name=jamel 22:20:18.983 [main] INFO bootstrap.MemcachedStandbyClientTest 37- name=jamel 22:20:18.989 [main] INFO bootstrap.MemcachedStandbyClientTest 42- repalce name=rain 22:20:18.995 [main] INFO bootstrap.MemcachedStandbyClientTest 45- append name=rain-han 22:20:19.004 [main] INFO bootstrap.MemcachedStandbyClientTest 48- prepend name=0-rain-han 22:20:22.012 [main] INFO bootstrap.MemcachedStandbyClientTest 56- after touch name=null 22:20:22.017 [main] INFO bootstrap.MemcachedStandbyClientTest 59- age=27 22:20:22.026 [main] INFO bootstrap.MemcachedStandbyClientTest 62- incr age=30 22:20:22.031 [main] INFO bootstrap.MemcachedStandbyClientTest 64- decr age=28 22:20:22.043 [main] INFO bootstrap.MemcachedStandbyClientTest 68- cas age=27 22:20:22.050 [main] INFO bootstrap.MemcachedStandbyClientTest 71- incrementAndGet counter,1 22:20:22.053 [main] INFO bootstrap.MemcachedStandbyClientTest 72- decrementAndGet counter,0 22:20:22.055 [main] INFO bootstrap.MemcachedStandbyClientTest 73- addAndGet counter,3 22:20:22.089 [main] INFO com.google.code.yanf4j.core.impl.AbstractController 486- Controller has been stopped. 22:20:22.089 [Xmemcached-Reactor-2] INFO com.google.code.yanf4j.core.impl.AbstractController 368- Remove a session: 192.168.126.128:11211