我使用的是CentOS 6.4系统,安装的Memcached版本为1.4.20。这里,记录一下安装配置的过程,以及如何使用一些经常使用的客户端来访问Memcached存储的数据。php
安装配置html
首先,编译、安装、配置libevent库,执行以下命令:java
1
2
3
4
5
6
7
|
wget https:
//github
.com
/downloads/libevent/libevent/libevent-1
.4.14b-stable.
tar
.gz
tar
xvzf libevent-1.4.14b-stable.
tar
.gz
ln
-s
/usr/local/libevent-1
.4.14b-stable
/usr/local/libevent
cd
/usr/local/libevent
.
/configure
make
make
install
|
而后,编译、安装、配置Memcached,执行以下命令行:node
1
2
3
4
5
6
|
wget http:
//www
.memcached.org
/files/memcached-1
.4.20.
tar
.gz
tar
xvzf memcached-1.4.20.
tar
.gz
ln
-s
/usr/local/memcached-1
.4.20
/usr/local/memcached
.
/configure
--with-libevent=
/usr/local/libevent/
make
make
install
|
若是没有出错,安装成功。git
管理memcached服务github
- 启动Memcached
通常状况下,简单地能够使用相似以下形式,启动Memcached服务:npm
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
|
上述命令行中,基于上面各个选项,以及其余一些选项的含义,说明以下表所示:api
选项 | 含义说明 |
-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的进程号:缓存
1
|
ps
-ef |
grep
memcached
|
而后杀掉Memcached服务进程:ruby
1
|
kill
-9 <PID>
|
-9表示强制杀掉进程。
Memcached启动之后,能够经过客户端来操做缓存中的数据,咱们说明一些经常使用的客户端,及其使用方法。
Telnet客户端
Telnet客户端能够经过命令行的方式来监控查看Memcached服务器存储数据的状况。例如,Memcached的服务地址为192.168.4.86:11211,能够telnet到该服务端口:
1
|
telnet 192.168.4.86 11211
|
若是链接成功,能够使用以下一些命令:
- stats命令
该命令用于显示服务器信息、统计数据等,结果示例数据(来自www.2cto.com网站),例如:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
|
STAT pid 22362 //memcache服务器的进程ID www.2cto.com
STAT uptime 1469315 //服务器已经运行的秒数
STAT time 1339671194 //服务器当前的unix时间戳
STAT version 1.4.9 //memcache版本
STAT libevent 1.4.9-stable //libevent版本
STAT pointer_size 64 //当前操做系统的指针大小(32位系统通常是32bit,64就是64位操做系统)
STAT rusage_user 3695.485200 //进程的累计用户时间
STAT rusage_system 14751.273465 //进程的累计系统时间
STAT curr_connections 69 //服务器当前存储的items数量
STAT total_connections 855430 //从服务器启动之后存储的items总数量
STAT connection_structures 74 //服务器分配的链接构造数
STAT reserved_fds 20 //
STAT cmd_get 328806688 //get命令(获取)总请求次数
STAT cmd_set 75441133 //set命令(保存)总请求次数 www.2cto.com
STAT cmd_flush 34 //flush命令请求次数
STAT cmd_touch 0 //touch命令请求次数
STAT get_hits 253547177 //总命中次数
STAT get_misses 75259511 //总未命中次数
STAT delete_misses 4 //delete命令未命中次数
STAT delete_hits 565730 //delete命令命中次数
STAT incr_misses 0 //incr命令未命中次数
STAT incr_hits 0 //incr命令命中次数
STAT decr_misses 0 //decr命令未命中次数
STAT decr_hits 0 //decr命令命中次数
STAT cas_misses 0 //cas命令未命中次数
STAT cas_hits 0 //cas命令命中次数
STAT cas_badval 0 //使用擦拭次数
STAT touch_hits 0 //touch命令未命中次数
STAT touch_misses 0 //touch命令命中次数
STAT auth_cmds 0 //认证命令处理的次数
STAT auth_errors 0 //认证失败数目
STAT bytes_read 545701515844 //总读取字节数(请求字节数)
STAT bytes_written 1649639749866 //总发送字节数(结果字节数)
STAT limit_maxbytes 2147483648 //分配给memcache的内存大小(字节)
STAT accepting_conns 1 //服务器是否达到过最大链接(0/1)
STAT listen_disabled_num 0 //失效的监听数
STAT threads 4 //当前线程数
STAT conn_yields 14 //链接操做主动放弃数目
STAT hash_power_level 16 //
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT expired_unfetched 30705763
STAT evicted_unfetched 0
STAT bytes 61380700 //当前存储占用的字节数
STAT curr_items 28786 //当前存储的数据总数
STAT total_items 75441133 //启动以来存储的数据总数
STAT evictions 0 //为获取空闲内存而删除的items数(分配给memcache的空间用满后须要删除旧的items来获得空间分配给新的items)
STAT reclaimed 39957976 //已过时的数据条目来存储新数据的数目
END
|
上面给出了各个统计项的含义说明,再也不累述。
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 | 重置统计信息 |
下面的命令,咱们经过表格的形式说明,以下表所示:
命令 | 用法格式 | 含义说明 | 示例 |
get | get <key>*\r\n | 用于获取缓存的数据,键为key。 | get name VALUE name 0 7 shirdrn END |
gets | gets <key>*\r\n | 用于获取缓存的数据,键为一组key。 | gets name hobby VALUE name 1 7 1234567 VALUE hobby 0 25 tenis basketball football END |
set | set <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 END |
touch | touch <key> <exptime> [noreply]\r\n | 更新缓存中key对应的值的过时时间。 | touch name 1800 |
delete | delete <key> [<time>] [noreply]\r\n | 给定键key,删除缓存中key对应的数据。 | delete name 60 |
add | add <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 |
replace | replace <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 END |
append | append <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 END |
prepend | prepend <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 END |
incr | incr <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 1000099 |
decr | decr <key> <value> [noreply]\r\n | 计数命令,能够在原来已经存在的数字上进行减法计算,计算并存储新的数值。 | get active_users VALUE active_users 0 7 1000099 END decr active_users 3456 996643 |
flush_all | flush_all [<time>] [noreply]\r\n | 使缓存中的数据项失效,可选参数是在多少秒后失效。 | flush_all 1800 |
version | version\r\n | 返回Memcached服务器的版本信息。 | version |
quit | quit\r\n | 退出telnet终端。 | quit |
Java客户端
能够使用Java语言编写代码来访问Memcached缓存。目前,能够使用的Java客户端不少,这里简单介绍几个。
- spymemcached客户端
示例代码,以下所示:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
package
org.shirdrn.spymemcached;
import
net.spy.memcached.AddrUtil;
import
net.spy.memcached.BinaryConnectionFactory;
import
net.spy.memcached.MemcachedClient;
import
net.spy.memcached.internal.OperationFuture;
public
class
TestSpymemcached {
public
static
void
main(String[] args)
throws
Exception {
String address =
"192.168.4.86:11211"
;
MemcachedClient client =
new
MemcachedClient(
new
BinaryConnectionFactory(),
AddrUtil.getAddresses(address));
String key =
"magic_words"
;
int
exp =
3600
;
String o =
"hello"
;
// set
OperationFuture<Boolean> setFuture = client.set(key, exp, o);
if
(setFuture.get()) {
// get
System.out.println(client.get(key));
// append
client.append(key,
" the world!"
);
System.out.println(client.get(key));
// prepend
client.prepend(key,
"Stone, "
);
System.out.println(client.get(key));
// replace
o =
"This is a test for spymemcached."
;
OperationFuture<Boolean> replaceFuture = client.replace(key, exp, o);
if
(replaceFuture.get()) {
System.out.println(client.get(key));
// delete
client.delete(key);
System.out.println(client.get(key));
}
}
client.shutdown();
}
}
|
更多用法,能够参考后面的连接。
- XMemcached客户端
示例代码,以下所示:
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
|
package
org.shirdrn.xmemcached;
import
java.io.File;
import
java.io.IOException;
import
java.io.Serializable;
import
java.net.InetSocketAddress;
import
java.util.Arrays;
import
java.util.List;
import
java.util.Map;
import
java.util.concurrent.ExecutorService;
import
java.util.concurrent.Executors;
import
java.util.concurrent.TimeoutException;
import
java.util.concurrent.atomic.AtomicLong;
import
net.rubyeye.xmemcached.CASOperation;
import
net.rubyeye.xmemcached.GetsResponse;
import
net.rubyeye.xmemcached.MemcachedClient;
import
net.rubyeye.xmemcached.XMemcachedClientBuilder;
import
net.rubyeye.xmemcached.command.BinaryCommandFactory;
import
net.rubyeye.xmemcached.exception.MemcachedException;
import
net.rubyeye.xmemcached.utils.AddrUtil;
public
class
UsingXMemcachedClient {
public
static
void
main(String[] args)
throws
IOException {
String servers =
"192.168.4.86:11211"
;
// build and create a client
XMemcachedClientBuilder builder =
new
XMemcachedClientBuilder(
AddrUtil.getAddresses(servers));
builder.setCommandFactory(
new
BinaryCommandFactory());
final
MemcachedClient client = builder.build();
// examples using client to operate
final
String key =
"ghost"
;
try
{
// add
client.add(key,
0
,
"Ghost wind blows!"
);
System.out.println(
"add & get: "
+ client.get(key));
// append
client.append(key,
" It's a lie."
);
System.out.println(
"append & get: "
+ client.get(key));
// prepend
client.prepend(key,
"Who's said?! "
);
System.out.println(
"prepend & get: "
+ client.get(key));
// replace
client.replace(key,
0
,
"Everything is nothing!"
);
System.out.println(
"replace & get: "
+ client.get(key));
// delete
client.delete(key);
System.out.println(
"delete & get: "
+ client.get(key));
// gets
List<String> keys = Arrays.asList(
new
String[] {
"key1"
,
"key2"
,
"key3"
});
for
(String k : keys) {
client.set(k,
3600
,
"v:"
+ System.nanoTime());
}
Map<String, GetsResponse<Object>> values = client.gets(keys);
for
(Map.Entry<String, GetsResponse<Object>> entry : values.entrySet()) {
System.out.println(
"key="
+ entry.getKey() +
", value="
+ entry.getValue().getValue());
}
// cas
final
AtomicLong seq =
new
AtomicLong(System.nanoTime());
ExecutorService pool = Executors.newCachedThreadPool();
for
(
int
i=
0
; i<
10
; i++) {
pool.execute(
new
Runnable() {
@Override
public
void
run() {
while
(
true
) {
CacheResult o =
new
CacheResult();
o.file =
new
File(
"/opt/status/servers.lst"
);
o.lastmodified = seq.incrementAndGet();
System.out.println(
"#"
+ Thread.currentThread().getId() +
"=>o: "
+ o);
try
{
client.set(key,
0
, o);
Thread.sleep(
100
);
}
catch
(TimeoutException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch
(InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
catch
(MemcachedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
}
Thread.sleep(
3000
);
for
(
int
i=
0
; i<
10
; i++) {
client.cas(key,
new
CASOperation<CacheResult>() {
@Override
public
int
getMaxTries() {
return
3
;
}
@Override
public
CacheResult getNewValue(
long
arg0, CacheResult result) {
CacheResult old = result;
CacheResult nu =
new
CacheResult();
nu.file = old.file;
nu.lastmodified = seq.incrementAndGet();
System.out.println(
"cas: old="
+ old +
", new="
+ nu);
return
result;
}
});
}
pool.shutdown();
// flush_all
client.flushAll();
// stats
List<InetSocketAddress> addresses = AddrUtil.getAddresses(servers);
for
(InetSocketAddress addr : addresses) {
Map<String, String> stats = client.stats(addr);
System.out.println(stats);
}
}
catch
(TimeoutException e) {
e.printStackTrace();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
catch
(MemcachedException e) {
e.printStackTrace();
}
synchronized
(client) {
try
{
client.wait();
}
catch
(InterruptedException e) {
e.printStackTrace();
}
}
}
static
class
CacheResult
implements
Serializable {
private
static
final
long
serialVersionUID = 3349686173080590047L;
private
File file;
private
long
lastmodified;
@Override
public
String toString() {
return
"file=["
+ file +
", lastmodified="
+ lastmodified +
"]"
;
}
}
}
|
Node.js客户端
Memcached客户端代码的逻辑都很是相似,这里对Node.js简单举例说明,代码以下所示:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
#!/usr/bin/env node
var
MemcachedClient = require(
'memcached'
);
// configure memcached client
var
servers = [
'192.168.4.86:11211'
];
var
client =
new
MemcachedClient(servers);
// access memcached servers
var
key =
'ghost'
;
// set
var
value =
'Ghost wind blows!'
;
client.set(key, 0, value,
function
(err) {
var
data =
'key='
+ key +
', value='
+ value;
if
(err) {
console.error(
'Fail to set: '
+ data);
}
else
{
console.log(
'Added: '
+ data);
}
});
// get
var
valueGot = client.get(key,
function
(err, data) {
var
dataGot =
'key='
+ key +
', valueGot='
+ data;
if
(err) {
console.error(
'Fail to get: '
+ dataGot);
}
else
{
console.log(
'Got: '
+ dataGot);
}
});
|
参考连接
- http://www.memcached.org
- https://code.google.com/p/memcached/wiki/NewStart
- http://www.memcached.org/files/memcached-1.4.20.tar.gz
- https://code.google.com/p/memcached/wiki/Clients
- https://github.com/downloads/libevent/
- https://github.com/downloads/libevent/libevent/libevent-1.4.14b-stable.tar.gz
- https://code.google.com/p/spymemcached/
- https://code.google.com/p/xmemcached/
- https://github.com/killme2008/xmemcached
- https://code.google.com/p/memcached/wiki/NewCommands
- http://www.2cto.com/os/201303/193264.html
- http://tech.idv2.com/tag/memcached/
- http://programcreek.com/java-api-examples/index.php?api=net.spy.memcached.MemcachedClient
- http://lzone.de/articles/memcached.htm
- http://blog.elijaa.org/?post/2010/05/21/Memcached-telnet-command-summary
- https://github.com/3rd-Eden/node-memcached
- https://www.npmjs.org/package/memcached