【翻译】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个请求没有得到想要的数据。

相关推荐