Memcached服务器安装、配置、使用详解

来源:互联网 发布:西电软件学院 编辑:程序博客网 时间:2024/06/05 20:14

我使用的是CentOS 6.4系统,安装的Memcached版本为1.4.20。这里,记录一下安装配置的过程,以及如何使用一些常用的客户端来访问Memcached存储的数据。

安装配置

首先,编译、安装、配置libevent库,执行如下命令:

1wget https://github.com/downloads/libevent/libevent/libevent-1.4.14b-stable.tar.gz
2tar xvzf libevent-1.4.14b-stable.tar.gz
3ln -s /usr/local/libevent-1.4.14b-stable /usr/local/libevent
4cd /usr/local/libevent
5./configure
6make
7make install

然后,编译、安装、配置Memcached,执行如下命令行:

1wget http://www.memcached.org/files/memcached-1.4.20.tar.gz
2tar xvzf memcached-1.4.20.tar.gz
3ln -s /usr/local/memcached-1.4.20 /usr/local/memcached
4./configure --with-libevent=/usr/local/libevent/
5make
6make install

如果没有出错,安装成功。

管理memcached服务

  • 启动Memcached

一般情况下,简单地可以使用类似如下形式,启动Memcached服务:

1/usr/local/bin/memcached -d -m 64 -I 20m -u root -l 192.168.4.86 -p 11211 -c 1024 -P /usr/local/memcached/memcached.pid

上述命令行中,基于上面各个选项,以及其他一些选项的含义,说明如下表所示:

选项含义说明-d指定memcached进程作为一个守护进程启动-m <num>指定分配给memcached使用的内存,单位是MB-u <username>运行memcached的用户-l <ip_addr>监听的服务器IP地址,如果有多个地址的话,使用逗号分隔,格式可以为“IP地址:端口号”,例如:-l 指定192.168.0.184:19830,192.168.0.195:13542;端口号也可以通过-p选项指定-p <num>Memcached监听的端口,要保证该端口号未被占用-c <num>设置最大运行的并发连接数,默认是1024-R <num>为避免客户端饿死(starvation),对连续达到的客户端请求数设置一个限额,如果超过该设置,会选择另一个连接来处理请求,默认为20-k设置锁定所有分页的内存,对于大缓存应用场景,谨慎使用该选项-P保存memcached进程的pid文件-s <file>指定Memcached用于监听的UNIX socket文件-a <perms>设置-s选项指定的UNIX socket文件的权限-U <num>指定监听UDP的端口,默认11211,0表示关闭-M当内存使用超出配置值时,禁止自动清除缓存中的数据项,此时Memcached不可以,直到内存被释放-r设置产生core文件大小-f <factor>用于计算缓存数据项的内存块大小的乘数因子,默认是1.25-n为缓存数据项的key、value、flag设置最小分配字节数,默认是48-C禁用CAS-h显示Memcached版本和摘要信息-v输出警告和错误信息-vv打印信息比-v更详细:不仅输出警告和错误信息,也输出客户端请求和响应信息-i打印libevent和Memcached的licenses信息-t <threads>指定用来处理请求的线程数,默认为4-D <char>用于统计报告中Key前缀和ID之间的分隔符,默认是冒号“:”-L尝试使用大内存分页(pages)-B <proto>指定使用的协议,默认行为是自动协商(autonegotiate),可能使用的选项有auto、ascii、binary。-I <size>覆盖默认的STAB页大小,默认是1M-F禁用flush_all命令-o <options>指定逗号分隔的选项,一般用于用于扩展或实验性质的选项
  • 停止Memcached

可以通过Linux的如下命令查询到Memcached的进程号:

1ps -ef | grep memcached

然后杀掉Memcached服务进程:

1kill -9 <PID>

-9表示强制杀掉进程。

Memcached启动以后,可以通过客户端来操作缓存中的数据,我们说明一些常用的客户端,及其使用方法。

Telnet客户端

Telnet客户端可以通过命令行的方式来监控查看Memcached服务器存储数据的情况。例如,Memcached的服务地址为192.168.4.86:11211,可以telnet到该服务端口:

1telnet 192.168.4.86 11211

如果连接成功,可以使用如下一些命令:

  • stats命令

该命令用于显示服务器信息、统计数据等,结果示例数据(来自www.2cto.com网站),例如:

01STAT pid 22362    //memcache服务器的进程ID  www.2cto.com
02STAT uptime 1469315    //服务器已经运行的秒数
03STAT time 1339671194    //服务器当前的unix时间戳
04STAT version 1.4.9    //memcache版本
05STAT libevent 1.4.9-stable    //libevent版本
06STAT pointer_size 64    //当前操作系统的指针大小(32位系统一般是32bit,64就是64位操作系统)
07STAT rusage_user 3695.485200    //进程的累计用户时间
08STAT rusage_system 14751.273465    //进程的累计系统时间
09STAT curr_connections 69    //服务器当前存储的items数量
10STAT total_connections 855430    //从服务器启动以后存储的items总数量
11STAT connection_structures 74    //服务器分配的连接构造数
12STAT reserved_fds 20    //
13STAT cmd_get 328806688    //get命令(获取)总请求次数
14STAT cmd_set 75441133    //set命令(保存)总请求次数  www.2cto.com
15STAT cmd_flush 34    //flush命令请求次数
16STAT cmd_touch 0    //touch命令请求次数
17STAT get_hits 253547177    //总命中次数
18STAT get_misses 75259511    //总未命中次数
19STAT delete_misses 4    //delete命令未命中次数
20STAT delete_hits 565730    //delete命令命中次数
21STAT incr_misses 0    //incr命令未命中次数
22STAT incr_hits 0    //incr命令命中次数
23STAT decr_misses 0    //decr命令未命中次数
24STAT decr_hits 0    //decr命令命中次数
25STAT cas_misses 0    //cas命令未命中次数
26STAT cas_hits 0        //cas命令命中次数
27STAT cas_badval 0    //使用擦拭次数
28STAT touch_hits 0    //touch命令未命中次数
29STAT touch_misses 0    //touch命令命中次数
30STAT auth_cmds 0    //认证命令处理的次数
31STAT auth_errors 0    //认证失败数目
32STAT bytes_read 545701515844        //总读取字节数(请求字节数)
33STAT bytes_written 1649639749866    //总发送字节数(结果字节数)
34STAT limit_maxbytes 2147483648        //分配给memcache的内存大小(字节)
35STAT accepting_conns 1            //服务器是否达到过最大连接(0/1)
36STAT listen_disabled_num 0    //失效的监听数
37STAT threads 4        //当前线程数
38STAT conn_yields 14    //连接操作主动放弃数目
39STAT hash_power_level 16    //
40STAT hash_bytes 524288
41STAT hash_is_expanding 0
42STAT expired_unfetched 30705763
43STAT evicted_unfetched 0
44STAT bytes 61380700    //当前存储占用的字节数
45STAT curr_items 28786    //当前存储的数据总数
46STAT total_items 75441133    //启动以来存储的数据总数
47STAT evictions 0    //为获取空闲内存而删除的items数(分配给memcache的空间用满后需要删除旧的items来得到空间分配给新的items)
48STAT reclaimed 39957976    //已过期的数据条目来存储新数据的数目
49END

上面给出了各个统计项的含义说明,不再累述。
stats命令有几个二级子项,说明如下表所示:

命令含义说明stats slabs显示各个slab的信息,包括chunk的大小、数目、使用情况等stats items显示各个slab中item的数目和最老item的年龄(最后一次访问距离现在的秒数)stats detail [on|off|dump]设置或者显示详细操作记录;
参数为on,打开详细操作记录;
参数为off,关闭详细操作记录;
参数为dump,显示详细操作记录(每一个键值get、set、hit、del的次数)stats malloc打印内存分配信息stats sizes打印缓存使用信息stats reset重置统计信息

下面的命令,我们通过表格的形式说明,如下表所示:

命令用法格式含义说明示例getget <key>*\r\n用于获取缓存的数据,键为key。get name
VALUE name 0 7
shirdrn
ENDgetsgets <key>*\r\n用于获取缓存的数据,键为一组key。gets name hobby
VALUE name 1 7
1234567
VALUE hobby 0 25
tenis basketball football
ENDsetset <key> <flags> <exptime> <bytes> [noreply]\r\n<value>\r\n向缓存中存储数据,不管key对应的值存在与否,都设置key对应的值。set name 0 1800 7
shirdrn
STORED
get name
VALUE name 0 7
shirdrn
ENDtouchtouch <key> <exptime> [noreply]\r\n更新缓存中key对应的值的过期时间。touch name 1800deletedelete <key> [<time>] [noreply]\r\n给定键key,删除缓存中key对应的数据。delete name 60addadd <key> <flags> <exptime> <bytes> [noreply]\r\n<value>\r\n向缓存中存储数据,只有key对应的值不存在时,才会设置key对应的值。add hobby 0 1800 10
basketball
STORED
get hobby

VALUE hobby 0 10
basketball
END

replacereplace <key> <flags> <exptime> <bytes> [noreply]\r\n<value>\r\n覆盖一个已经存在Key及其对应的Value,替换一定要保证替换后的值的长度原始长度相同,否则replace失败。get name
VALUE name 0 7
shirdrn
END
replace name 0 1800 7
youak47
STORED
get name
VALUE name 0 7
youak47
ENDappendappend <key> <flags> <exptime> <bytes> [noreply]\r\n<value>\r\n在一个已经存在的数据值(value)上追加,是在数据值的后面追加。get hobby
VALUE hobby 0 10
basketball
END
append hobby 0 1800 9
football
STORED
get hobby
VALUE hobby 0 19
basketball football
ENDprependprepend <key> <flags> <exptime> <bytes> [noreply]\r\n<value>\r\n在一个已经存在的数据值(value)上追加,是在数据值的前面追加。get hobby
VALUE hobby 0 19
basketball football
END
prepend hobby 0 1800 6
tenis
STORED
get hobby
VALUE hobby 0 25
tenis basketball football
ENDincrincr <key> <value> [noreply]\r\n计数命令,可以在原来已经存在的数字上进行累加求和,计算并存储新的数值。set active_users 0 1000000 7
1000000
STORED
get active_users
VALUE active_users 0 7
1000000
END
incr active_users 99
1000099decrdecr <key> <value> [noreply]\r\n计数命令,可以在原来已经存在的数字上进行减法计算,计算并存储新的数值。get active_users
VALUE active_users 0 7
1000099
END
decr active_users 3456
996643flush_allflush_all [<time>] [noreply]\r\n使缓存中的数据项失效,可选参数是在多少秒后失效。flush_all 1800versionversion\r\n返回Memcached服务器的版本信息。versionquitquit\r\n退出telnet终端。quit

Java客户端

可以使用Java语言编写代码来访问Memcached缓存。目前,可以使用的Java客户端很多,这里简单介绍几个。

  • spymemcached客户端

示例代码,如下所示:

01package org.shirdrn.spymemcached;
02 
03import net.spy.memcached.AddrUtil;
04import net.spy.memcached.BinaryConnectionFactory;
05import net.spy.memcached.MemcachedClient;
06import net.spy.memcached.internal.OperationFuture;
07 
08public class TestSpymemcached {
09 
10     public static void main(String[] args) throws Exception {
11          String address = "192.168.4.86:11211";
12          MemcachedClient client = new MemcachedClient(new BinaryConnectionFactory(),
13                    AddrUtil.getAddresses(address));
14          
15          String key = "magic_words";
16          int exp = 3600;
17          String o = "hello";
18          // set
19          OperationFuture<Boolean> setFuture = client.set(key, exp, o);
20          if(setFuture.get()) {
21               // get
22               System.out.println(client.get(key));
23               
24               // append
25               client.append(key, " the world!");
26               System.out.println(client.get(key));
27               
28               // prepend
29               client.prepend(key, "Stone, ");
30               System.out.println(client.get(key));
31               
32               // replace
33               o = "This is a test for spymemcached.";
34               OperationFuture<Boolean> replaceFuture = client.replace(key, exp, o);
35               if(replaceFuture.get()) {
36                    System.out.println(client.get(key));
37                    
38                    // delete
39                    client.delete(key);
40                    System.out.println(client.get(key));
41               }
42          }
43          
44          client.shutdown();
45     }
46 
47}

更多用法,可以参考后面的链接。

  • XMemcached客户端

示例代码,如下所示:

001package org.shirdrn.xmemcached;
002 
003import java.io.File;
004import java.io.IOException;
005import java.io.Serializable;
006import java.net.InetSocketAddress;
007import java.util.Arrays;
008import java.util.List;
009import java.util.Map;
010import java.util.concurrent.ExecutorService;
011import java.util.concurrent.Executors;
012import java.util.concurrent.TimeoutException;
013import java.util.concurrent.atomic.AtomicLong;
014 
015import net.rubyeye.xmemcached.CASOperation;
016import net.rubyeye.xmemcached.GetsResponse;
017import net.rubyeye.xmemcached.MemcachedClient;
018import net.rubyeye.xmemcached.XMemcachedClientBuilder;
019import net.rubyeye.xmemcached.command.BinaryCommandFactory;
020import net.rubyeye.xmemcached.exception.MemcachedException;
021import net.rubyeye.xmemcached.utils.AddrUtil;
022 
023public class UsingXMemcachedClient {
024 
025     public static void main(String[] args) throws IOException {
026          String servers = "192.168.4.86:11211";
027          // build and create a client
028          XMemcachedClientBuilder builder = new XMemcachedClientBuilder(
029                    AddrUtil.getAddresses(servers));
030          builder.setCommandFactory(new BinaryCommandFactory());
031          final MemcachedClient client = builder.build();
032          
033          // examples using client to operate
034          final String key = "ghost";
035          try {
036               // add
037               client.add(key, 0"Ghost wind blows!");
038               System.out.println("add & get: " + client.get(key));
039               
040               // append
041               client.append(key, " It's a lie.");
042               System.out.println("append & get: " + client.get(key));
043               
044               // prepend
045               client.prepend(key, "Who's said?! ");
046               System.out.println("prepend & get: " + client.get(key));
047               
048               // replace
049               client.replace(key, 0"Everything is nothing!");
050               System.out.println("replace & get: " + client.get(key));
051               
052               // delete
053               client.delete(key);
054               System.out.println("delete & get: " + client.get(key));
055               
056               // gets
057               List<String> keys = Arrays.asList(new String[] {
058                         "key1""key2""key3"
059               });
060               for(String k : keys) {
061                    client.set(k, 3600"v:" + System.nanoTime());
062               }
063               Map<String, GetsResponse<Object>> values = client.gets(keys);
064               for(Map.Entry<String, GetsResponse<Object>> entry : values.entrySet()) {
065                    System.out.println("key=" + entry.getKey() + ", value=" + entry.getValue().getValue());
066               }
067               
068               // cas
069               final AtomicLong seq = new AtomicLong(System.nanoTime());
070               ExecutorService pool = Executors.newCachedThreadPool();
071               for(int i=0; i<10; i++) {
072                    pool.execute(new Runnable() {
073                         @Override
074                         public void run() {
075                              while(true) {
076                                   CacheResult o = new CacheResult();
077                                   o.file = new File("/opt/status/servers.lst");
078                                   o.lastmodified = seq.incrementAndGet();
079                                   System.out.println("#" + Thread.currentThread().getId() + "=>o: " + o);
080                                   try {
081                                        client.set(key, 0, o);
082                                        Thread.sleep(100);
083                                   catch (TimeoutException e) {
084                                        // TODO Auto-generated catch block
085                                        e.printStackTrace();
086                                   catch (InterruptedException e) {
087                                        // TODO Auto-generated catch block
088                                        e.printStackTrace();
089                                   catch (MemcachedException e) {
090                                        // TODO Auto-generated catch block
091                                        e.printStackTrace();
092                                   }
093                              }
094                         }
095                    });
096               }
097               Thread.sleep(3000);
098               for(int i=0; i<10; i++) {
099                    client.cas(key, new CASOperation<CacheResult>() {
100                         @Override
101                         public int getMaxTries() {
102                              return 3;
103                         }
104                         @Override
105                         public CacheResult getNewValue(long arg0, CacheResult result) {
106                              CacheResult old = result;
107                              CacheResult nu = new CacheResult();
108                              nu.file = old.file;
109                              nu.lastmodified = seq.incrementAndGet();
110                              System.out.println("cas: old=" + old + ", new=" + nu);
111                              return result;
112                         }
113                    });
114               }
115               pool.shutdown();
116               
117               // flush_all
118              client.flushAll();
119               
120               // stats
121               List<InetSocketAddress> addresses = AddrUtil.getAddresses(servers);
122               for(InetSocketAddress addr : addresses) {
123                    Map<String, String> stats = client.stats(addr);
124                    System.out.println(stats);
125               }
126               
127          catch (TimeoutException e) {
128               e.printStackTrace();
129          catch (InterruptedException e) {
130               e.printStackTrace();
131          catch (MemcachedException e) {
132               e.printStackTrace();
133          }
134          
135          synchronized(client) {
136               try {
137                    client.wait();
138               catch (InterruptedException e) {
139                    e.printStackTrace();
140               }
141          }
142 
143     }
144     
145     static class CacheResult implements Serializable {
146          private static final long serialVersionUID = 3349686173080590047L;
147          private File file;
148          private long lastmodified;
149          @Override
150          public String toString() {
151               return "file=[" + file + ", lastmodified=" + lastmodified + "]";
152          }
153     }
154 
155}

Node.js客户端

Memcached客户端代码的逻辑都非常类似,这里对Node.js简单举例说明,代码如下所示:

查看源代码
打印帮助
01#!/usr/bin/env node
02 
03var MemcachedClient = require('memcached');
04 
05// configure memcached client
06var servers = ['192.168.4.86:11211'];
07var client = new MemcachedClient(servers);
08 
09// access memcached servers
10var key = 'ghost';
11 
12// set
13var value = 'Ghost wind blows!';
14client.set(key, 0, value, function(err) {
15     var data = 'key=' + key + ', value=' + value;
16     if(err) {
17          console.error('Fail to set: ' + data);
18     else {
19          console.log('Added: ' + data);
20     }
21});
22 
23// get
24var valueGot = client.get(key, function(err, data) {
25     var dataGot = 'key=' + key + ', valueGot=' + data;
26     if(err) {
27                console.error('Fail to get: ' + dataGot);
28        else {
29                console.log('Got: ' + dataGot);
30        }
31});

参考链接

0 0