一、安装
1、安装libevent
root@wxlccsu:# tar vxzf libevent-2.0.9-rc.tar.gz
root@wxlccsu:# cd libevent-2.0.9
root@wxlccsu:# ./configure --prefix=/usr/
root@wxlccsu:# make
root@wxlccsu:# make install
root@wxlccsu:# make
root@wxlccsu:# make install
安装完之后要启动服务
root@wxlccsu:# /usr/local/bin/memcached -d -m 64 -u root -p 20002 -c 128 –P
启动memcached出现状况
error while loading shared libraries: libevent-2.0.so.5: cannot open shared object file: No such file or directory
在网上查了下
解决这个问题有如下方法:
1>首先 find / -name libevent-2.0.so.5 找到缺少的链接文件到底在那儿。
2> LD_DEBUG=libs /usr/local/memcached/bin/memcached -v
3> 从Debug信息中就知道程序去×××链接库了。我这边程序去 trying file=/usr/lib/libevent-2.0.so.5 而我的链接库的实际存储位置是 /usr/local/lib/libevent-2.0.so.5
4>做一个软连接 ln -s /usr/local/lib/libevent-2.0.so.5 /usr/lib/libevent-2.0.so.
5>搞定.
出错误后另外一种安装
tar -xzvf memcached-1.4.4.tar.gz
配置:
cd memcached-1.4.4
./configure –with-libevent=/usr/
备注:如果 libevent 不是安装在 /usr 目录下,那么需要把 libevent-1.4a.so.1 拷贝/链接到 /usr/lib 中,否则memcached在配置的时候会报找不到libevent。
启动参数说明:
-d 选项是启动一个守护进程,
-m 是分配给Memcache使用的内存数量,单位是MB,默认64MB
-M return error on memory exhausted (rather than removing items)
-u 是运行Memcache的用户,如果当前为root 的话,需要使用此参数指定用户。
-l 是监听的服务器IP地址,默认为所有网卡。
-p 是设置Memcache的TCP监听的端口,最好是1024以上的端口
-c 选项是最大运行的并发连接数,默认是1024
-P 是设置保存Memcache的pid文件
-f chunk size growth factor (default: 1.25)
-I Override the size of each slab page. Adjusts max item size(1.4.2版本新增)默认设置为1M,新版本可以更改。
3、启动memcached
/usr/local/bin/memcached -d -m 64 -u root -p 20002 -c 128 –P
4、检查是否正常启动
[root@localhost tmp]# ps auxxww|grep mememcached
root 3565 0.0 0.1 4176 708 pts/1 R+ 00:35 0:00 grep mememcached
[root@localhost tmp]# telnet localhost 20004
Trying 127.0.0.1...
Connected to localhost.localdomain (127.0.0.1).
Escape character is '^]'.
stats
STAT pid 3381
STAT uptime 1961
STAT time 1299083860
STAT version 1.4.5
STAT pointer_size 32
STAT rusage_user 0.000000
5、检查启动进程ps -ef|grep mem
root 3258 1 0 Mar02 ? 00:00:00 /usr/local/bin/memcached -d -m 64 -u root -p 20002
6、设置开机自动启动
vi /etc/rc.d/rc.local
然后在最后增加一句
/usr/local/bin/memcached -d -m 64 -u root -p 20002 –P
7、服务自启动脚本
#!/bin/bash
mm_bin="/usr/local/bin/memcached"
mm_log="/tmp/memcached_check.log"
mm_ports=("20002" "20004")
mm_param=("-d -m 64 -u root -p 20002 -l 127.0.0.1" "-d -m 64 -u root -p 20004 -l 127.0.0.1")
mm_count=${#mm_ports[@]}
t=$(date -d "today" +"%Y-%m-%d %H:%M:%S")
i=0
while [ $i -lt $mm_count ]
do
mm_exists=`ps -ef|grep "memcached"|grep "${mm_ports[$i]}"|grep -v grep|wc -l`
if [ "$mm_exists" == "0" ]; then
${mm_bin} ${mm_param[$i]} 2>&1 > /dev/null &
echo "${t} : ${mm_bin} ${mm_param[$i]}" >> ${mm_log}
fi
let i++
done
8、停止Memcache进程:
killall -9 memcached
Page为内存分配的最小单位。
Memcached的内存分配以page为单位,默认情况下一个page是1M,可以通过-I参数在启动时指定。如果需要申请内存时,memcached会划分出一个新的page并分配给需要的slab区域。page一旦被分配在重启前不会被回收或者重新分配(page ressign已经从1.2.8版移除了)
二、Memecached 性能高参数
stats 状态信息解释
STAT pid 1552
STAT uptime 3792
STAT time 1262517674
STAT version 1.2.6
STAT pointer_size 32
STAT curr_items 1
STAT total_items 2
STAT bytes 593
STAT curr_connections 2
STAT total_connections 28
STAT connection_structures 9
STAT cmd_get 3
STAT cmd_set 2
STAT get_hits 2
STAT get_misses 1
STAT evictions 0
STAT bytes_read 1284
STAT bytes_written 5362
STAT limit_maxbytes 67108864
STAT threads 1
END
这里显示了很多状态信息,下边详细解释每个状态项:
1. pid: memcached服务进程的进程ID
2. uptime: memcached服务从启动到当前所经过的时间,单位是秒。
3. time: memcached服务器所在主机当前系统的时间,单位是秒。
4. version: memcached组件的版本。这里是我当前使用的1.2.6。
5. pointer_size:服务器所在主机操作系统的指针大小,一般为32或64.
6. curr_items:表示当前缓存中存放的所有缓存对象的数量。不包括目前已经从缓存中删除的对象。
7. total_items:表示从memcached服务启动到当前时间,系统存储过的所有对象的数量,包括目前已经从缓存中删除的对象。
8. bytes:表示系统存储缓存对象所使用的存储空间,单位为字节。
9. curr_connections:表示当前系统打开的连接数。
10. total_connections:表示从memcached服务启动到当前时间,系统打开过的连接的总数。
11. connection_structures:表示从memcached服务启动到当前时间,被服务器分配的连接结构的数量,这个解释是协议文档给的,具体什么意思,我目前还没搞明白。
12. cmd_get:累积获取数据的数量,这里是3,因为我测试过3次,第一次因为没有序列化对象,所以获取数据失败,是null,后边有2次是我用不同对象测试了2次。
13. cmd_set:累积保存数据的树立数量,这里是2.虽然我存储了3次,但是第一次因为没有序列化,所以没有保存到缓存,也就没有记录。
14. get_hits:表示获取数据成功的次数。
15. get_misses:表示获取数据失败的次数。
16. evictions:为了给新的数据项目释放空间,从缓存移除的缓存对象的数目。比如超过缓存大小时根据LRU算法移除的对象,以及过期的对象。
17. bytes_read:memcached服务器从网络读取的总的字节数。
18. bytes_written:memcached服务器发送到网络的总的字节数。
19. limit_maxbytes:memcached服务缓存允许使用的最大字节数。这里为67108864字节,也就是是64M.与我们启动memcached服务设置的大小一致。
20. threads:被请求的工作线程的总数量。
这个命令中比较关键的属性是get_hits和get_misses,get_hits表示读取cache命中的次数,get_misses是读取失败的次数,即尝试读取不存在的缓存数据。
三、使用Growth Factor进行调优
Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。
这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。例如,将100字节
的数据缓存到128字节的chunk中,剩余的28字节就浪费了
memcached在启动时指定Growth Factor因子(通过f
选项),就可以在某种程度上控制slab之间的
差异。默认值为1.25。但是,在该选项出现之前,这个因子曾经固定为2,称为“powers of 2”策略。
/usr/local/bin/memcached -u root -f 2 –vv
四.查看slabs的使用状况
Vi memcached-tool
#!/usr/bin/perl
#
# memcached-tool:
# stats/management tool for memcached.
#
# Author:
# Brad Fitzpatrick <brad@danga.com>
#
# License:
# public domain. I give up all rights to this
# tool. modify and copy at will.
#
use strict;
use IO::Socket::INET;
my $host = shift;
my $mode = shift || "display";
my ($from, $to);
if ($mode eq "display") {
undef $mode if @ARGV;
} elsif ($mode eq "move") {
$from = shift;
$to = shift;
undef $mode if $from < 6 || $from > 17;
undef $mode if $to < 6 || $to > 17;
print STDERR "ERROR: parameters out of range\n\n" unless $mode;
} elsif ($mode eq 'dump') {
;
} elsif ($mode eq 'stats') {
;
} else {
undef $mode;
}
undef $mode if @ARGV;
die
"Usage: memcached-tool <host[:port]> [mode]\n
memcached-tool 10.0.0.5:11211 display # shows slabs
memcached-tool 10.0.0.5:11211 # same. (default is display)
memcached-tool 10.0.0.5:11211 stats # shows general stats
memcached-tool 10.0.0.5:11211 move 7 9 # takes 1MB slab from class #7
# to class #9.
You can only move slabs around once memory is totally allocated, and only
once the target class is full. (So you can't move from #6 to #9 and #7
to #9 at the same itme, since you'd have to wait for #9 to fill from
the first reassigned page)
" unless $host && $mode;
$host .= ":11211" unless $host =~ /:\d+/;
my $sock = IO::Socket::INET->new(PeerAddr => $host,
Proto => 'tcp');
die "Couldn't connect to $host\n" unless $sock;
if ($mode eq "move") {
my $tries = 0;
while (1) {
print $sock "slabs reassign $from $to\r\n";
my $res = <$sock>;
$res =~ s/\s+//;
if ($res eq "DONE") {
print "Success.\n";
exit 0;
} elsif ($res eq "CANT") {
print "Error: can't move from $from to $to. Destination not yet full? See usage docs.\n";
exit;
} elsif ($res eq "BUSY") {
if (++$tries == 3) {
print "Failed to move after 3 tries. Try again later.\n";
exit;
}
print "Page busy, retrying...\n";
sleep 1;
}
}
exit;
}
if ($mode eq 'dump') {
my %items;
my $totalitems;
print $sock "stats items\r\n";
while (<$sock>) {
last if /^END/;
if (/^STAT items:(\d*):number (\d*)/) {
$items{$1} = $2;
$totalitems += $2;
}
}
print STDERR "Dumping memcache contents\n";
print STDERR " Number of buckets: " . scalar(keys(%items)) . "\n";
print STDERR " Number of items : $totalitems\n";
foreach my $bucket (sort(keys(%items))) {
print STDERR "Dumping bucket $bucket - " . $items{$bucket} . " total items\n";
print $sock "stats cachedump $bucket $items{$bucket} 1\r\n";
my %keyexp;
while (<$sock>) {
last if /^END/;
# return format looks like this
# ITEM foo [6 b; 1176415152 s]
if (/^ITEM (\S+) \[.* (\d+) s\]/) {
$keyexp{$1} = $2;
}
}
foreach my $k (keys(%keyexp)) {
my $val;
print $sock "get $k\r\n";
my $response = <$sock>;
$response =~ /VALUE (\S+) (\d+) (\d+)/;
my $flags = $2;
my $len = $3;
read $sock, $val , $len;
# get the END
$_ = <$sock>;
$_ = <$sock>;
print "add $k $flags $keyexp{$k} $len\r\n$val\r\n";
}
}
exit;
}
if ($mode eq 'stats') {
my %items;
print $sock "stats\r\n";
while (<$sock>) {
last if /^END/;
chomp;
if (/^STAT\s+(\S*)\s+(.*)/) {
$items{$1} = $2;
}
}
printf ("#%-17s %5s %11s\n", $host, "Field", "Value");
foreach my $name (sort(keys(%items))) {
printf ("%24s %12s\n", $name, $items{$name});
}
exit;
}
# display mode:
my %items; # class -> { number, age, chunk_size, chunks_per_page,
# total_pages, total_chunks, used_chunks,
# free_chunks, free_chunks_end }
print $sock "stats items\r\n";
while (<$sock>) {
last if /^END/;
if (/^STAT items:(\d+):(\w+) (\d+)/) {
$items{$1}{$2} = $3;
}
}
print $sock "stats slabs\r\n";
while (<$sock>) {
last if /^END/;
if (/^STAT (\d+):(\w+) (\d+)/) {
$items{$1}{$2} = $3;
}
}
print " # Item_Size Max_age 1MB_pages Count Full?\n";
foreach my $n (1..40) {
my $it = $items{$n};
next if (0 == $it->{total_pages});
my $size = $it->{chunk_size} < 1024 ? "$it->{chunk_size} B " :
sprintf("%.1f kB", $it->{chunk_size} / 1024.0);
my $full = $it->{free_chunks_end} == 0 ? "yes" : " no";
printf "%3d %8s %7d s %7d %7d %7s\n",
$n, $size, $it->{age}, $it->{total_pages},
$it->{number}, $full;
}
./memcached-tool 172.16.23.172:20002
影响Memcached读取命中率的因素
1.内存分配大小,如果不够,影响因为被LRU置换了。
2.缓存策略影响。比如某个对象的缓存失效时间太短,可能导致命中率下降。
3.分布式缓存节点故障(一致性哈希已尽量减小影响)
第一次获取,缓存读取命中率为0.因为缓存中不存在。然后会往缓存中设置对象。第二次命中,就是50%。
理想状态:
1.内存空间足够大
2.miss都是第一次从DB加载的情况。实际上不可能,但是一个努力的目标
对于memcached实现session共享。由于session本身有失效期,一个用户可能产生多个session。相对来讲,
这样的设计命中率可能不会太高。可单独配置,不影响其他业务缓存统计。
|