我使用的是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