一、安装

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
2、安装Memcached
root@wxlccsu:# tar vxzf memcached-1.4.5.tar.gz
root@wxlccsu:# cd memcached-1.4.5
root@wxlccsu:#
./configure –with-libevent=/usr/
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 是设置MemcacheTCP监听的端口,最好是1024以上的端口
-c 选项是最大运行的并发连接数,默认是1024
-P 是设置保存Memcachepid文件 
-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
 
添加为自动执行:
    #crontab -e
*/10 * * * * /home/liuwanbing/memcached_check.sh


系统每10分钟会自动执行memcached_check.sh
 
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_hitsget_missesget_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。相对来讲,
这样的设计命中率可能不会太高。可单独配置,不影响其他业务缓存统计。