【翻译】Memcache 的使用
前几天接触到memcache的,这里学习下。希望看到这个文章的人能够纠错和补充。
http://sacharya.com/
前面写的是JBoss Cache和Memcached的比较。从而肯定了Memcached的简单,资源消耗小,便于维护的优点。
简介:
Memcached的优点:简单、独立、便于维护。
Memcached服务是一个内存缓存。它可以通过键值对存储包括字节、文档、原语等信息。想其他缓存一样,存储数据到内存中。从而当用户请求数据的时候,阻止用户区访问数据库、文件系统以及其他后端系统。这样就降低了后端系统的负载。提高了系统的扩展性。当数据存储到到内存后,访问数据时就会比昂贵的后天服务要快很多。
然而,Memcached并不是不变的存储空间。而且并不保证数据就一定会在缓存中,尽管你确实将数据存进去了。所以不要完全相信缓存。
Memcached的唯一一个限制就是cache的key的字符长度不能超过255个。并且被存储的值不能超过1MB。
安装:
1、安装Libevent:
Memcached使用Libevent库来处理网络IO。
$ cd libevent-1.4.11-stable $ autoconf $ ./configure --prefix=/usr/local $ make $ sudo make install
2、安装Memcached:
从 Danga.com下载最新版本的Memcached。
$ cd memcached-1.4.0 $ autoconf $ ./configure --prefix=/usr/local $ make $ sudo make install
3、运行Memcached:
在11211端口启动512MB的守护线程,然后你就能通过端口远程登录到服务,使用一些操作命令。
$memcached -d -m 512 127.0.0.1 -p 1121 $ telnet localhost 11211 Trying ::1... Connected to localhost. Escape character is '^]'. get joe END set joe 0 3600 10 (Note: TTL 3600 and 10 bytes) California STORED get joe VALUE joe 0 10 California END
java Memcached 客户端:
可以在下面两个连接中下载客户端:http://code.google.com/p/spymemcached/ https://github.com/gwhalin/Memcached-Java-Client/wiki/ 这里使用了后者。连接中可以找到相应的API。
MemcachedClient c=new MemcachedClient(new InetSocketAddress("127.0.0.1", 11211)); c.set("someKey", 3600, someObject); Object myObject=c.get("someKey"); c.delete("someKey")
Memcached客户端是单线程的,set方法通过键值将值放到cache中。如果一个值已经在cache中存在就,原来的值就会被重写。set方法还设置了这个值的存活时间。
添加或者移除缓存服务:
如果你需要升级系统,给cache添加一个服务器。你只需要将新增加的服务器的ip和端口添加到现有的服务器中中的“池”里。memcached服务客户端,就会将它记录下来。相反如果你想去掉一个服务器,只需要将“池”中的ip和端口删除。这样会让数据命中失败一小段时间。这个数据不久就会恢复到其他服务器上面。如果你担心访问数据库,你可以在缓存服务器去掉后,将数据倒到其他服务器上面。
MemcachedClient c = new MemcachedClient(new BinaryConnectionFactory(), AddrUtil.getAddresses("server1:11211 server2:11211"));
链接到“池”:
Memcached 建立的是TCP链接(Facebook 已经发布了一个Memcache的修改版本,使用的是UDP,去减少链接次数)来链接到Memcached服务。所以你想知道有多少服务链接被使用。
$ netstat -na | grep 11211 tcp4 0 0 127.0.0.1.11211 127.0.0.1.59321 ESTABLISHED tcp4 0 0 127.0.0.1.59321 127.0.0.1.11211 ESTABLISHED
没有确切的方法去关闭链接,因为set和get方法都是动态的。我喜欢固定的链接,并且重用这些链接。这样可以防止建立TCP链接照成的开销。
Mycache单例:
这是我封装memcached的代码:
01.import net.spy.memcached.AddrUtil; 02.import net.spy.memcached.BinaryConnectionFactory; 03.import net.spy.memcached.MemcachedClient; 04. 05.public class MyCache { 06.private static final String NAMESPACE= "SACHARYA:5d41402abc4b2a76b9719d91101"; 07.private static MyCache instance = null; 08.private static MemcachedClient[] m = null; 09. 10.private MyCache() { 11.try { 12.m= new MemcachedClient[21]; 13.for (int i = 0; i <= 20; i ++) { 14.MemcachedClient c = new MemcachedClient( 15.new BinaryConnectionFactory(), 16.AddrUtil.getAddresses("127.0.0.1:11211")); 17.m[i] = c; 18.} 19.} catch (Exception e) { 20. 21.} 22.} 23. 24.public static synchronized MyCache getInstance() { 25.System.out.println("Instance: " + instance); 26.if(instance == null) { 27.System.out.println("Creating a new instance"); 28.instance = new MyCache(); 29.} 30.return instance; 31.} 32. 33.public void set(String key, int ttl, final Object o) { 34.getCache().set(NAMESPACE + key, ttl, o); 35.} 36. 37.public Object get(String key) { 38.Object o = getCache().get(NAMESPACE + key); 39.if(o == null) { 40.System.out.println("Cache MISS for KEY: " + key); 41.} else { 42.System.out.println("Cache HIT for KEY: " + key); 43.} 44.return o; 45.} 46. 47.public Object delete(String key) { 48.return getCache().delete(NAMESPACE + key); 49.} 50. 51.public MemcachedClient getCache() { 52.MemcachedClient c= null; 53.try { 54.int i = (int) (Math.random()* 20); 55.c = m[i]; 56.} catch(Exception e) { 57. 58.} 59.return c; 60.} 61.}
在上面的代码:
1、 我使用了BinaryConnectionFactory,这个一个新功能,它使用了新的字节流协议。使解析文本更加有效。
2、MyCache是一个单例,但它被实例化的时候会建立21个链接。
3、我的key的格式是:SACHARYA:5d41402abc4b2a76b9719d91101:key。SACHARYA是我们域。这样我就可以使用相同的cache服务存储我的不同应用的数据。第二个随即字符串是为了隐藏key。最后就产生了数据的唯一标识。
简单使用:
通常情况下,你可以在系统瓶颈处使用cache。
01.public List<Product> getAllProducts() { 02.List<Product> products = (List<Product>) MyCache.getInstance().get("AllProducts"); 03.if(products != null) { 04.return products; 05.} 06.products = getAllProductsFromDB() 07.if(products) { 08.MyCache.getInstance().put("AllProducts", 3600, customer); 09.} 10.return products; 11.} 12. 13.public void updateProduct(String id) { 14.updateProductIntoDB(id) 15.MyCache.getInstance().delete("AllProducts"); 16.} 17.public void deleteProduct(String id) { 18.deleteProductFromDB(id) 19.MyCache.getInstance().delete("AllProducts");
缓存警告:
当应用第一次启动的时候,cache中没有数据。所以你可以通过一个调度程序预热cache。防止开始时大量访问端点(如数据库)。
监控cache效率:
stats命令提供了重要的信息,这些信息可以告诉你cache的执行情况。它显示了所有的get请求,以及多少命中成功,多少命中失败。
$ telnet localhost 11211 stats STAT cmd_get 13219 STAT get_hits 12232 STAT get_misses 512
以上显示的意思是总共有13219个请求,其中有12232请求得到了想要的数据(命中)。有512个请求没有得到想要的数据。