高效缓存服务器Memcached(一)

一、Memcached

1、memcached 是什么

   Memcached是一款开源、高性能、分布式内存对象缓存系统,可应用各种需要缓存的场景,其主要目的是通过降低对Database的访问来加速web应用程序。它是一个基于内存的“键值对”存储,用于存储数据库调用、API调用或页面引用结果的直接数据,如字符串、对象等。Memcached是以LiveJournal旗下Danga Interactive 公司的Brad Fitzpatric 为首开发的一款软件。现在已成为mixi、hatena、Facebook、Vox、LiveJournal等众多服务中提高Web应用扩展性的重要因素。

   许多Web应用都将数据保存到RDBMS(关系型数据库管理系统)中,应用服务器从中读取数据并在浏览器中显示。 但随着数据量的增大、访问的集中,就会出现RDBMS的负担加重、数据库响应恶化、 网站显示延迟等重大影响。这时就该memcached大显身手了。memcached是高性能的分布式内存缓存服务器。 一般的使用目的是,通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度、 提高可扩展性。如下图:

wKiom1YEAl7RV-qnAAEWf3sN1Q8556.jpg

2、memcached 特点

Memcached是一款开发工具,它既不是一个代码加速器,也不是数据库中间件。其设计哲学思想主要反映在如下方面:

  • 简单key/value存储:服务器不关心数据本身的意义及结构,只要是可序列化数据即可。存储项由“键、过期时间、可选的标志及数据”四个部分组成; 

  • 功能的实现一半依赖于客户端,一半基于服务器端:客户负责发送存储项至服务器端、从服务端获取数据以及无法连接至服务器时采用相应的动作;服务端负责接收、存储数据,并负责数据项的超时过期; 

  • 各服务器间彼此无视:不在服务器间进行数据同步; 

  • O(1)的执行效率 。

  • 清理超期数据:默认情况下,Memcached是一个LRU缓存,同时,它按事先预订的时长清理超期数据;但事实上,memcached不会删除任何已缓存数据,只是在其过期之后不再为客户所见;而且,memcached也不会真正按期限清理缓存,而仅是当get命令到达时检查其时长;

3、memcached 基于libevent的事件处理

   libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥O(1)的性能。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。 

4、memcached 内置内存存储方式

   为了提高性能,memcached中保存的数据都存储在memcached内置的内存存储空间中。由于数据仅存在于内存中,因此重启memcached、重启操作系统会导致全部数据消失。另外,内容容量达到指定值之后,就基于LRU(Least Recently Used)算法自动删除不使用的缓存。memcached本身是为缓存而设计的服务器,因此并没有过多考虑数据的永久性问题。

  • 数据存储方式:Slab Allocation    

结构图如下:    

wKioL1YEApiRZs39AADK05OIgRI755.jpg

 Slab Allocator的基本原理是按照预先规定的大小,将分配的内存分割成特定长度的块(chunk),并把尺寸相同的块分成组,以完全解决内存碎片问题。但由于分配的是特定长度的内存,因此无法有效利用分配的内存。比如将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。

  • Slab Allocator 相关术语

Page:分配给Slab的内存空间,默认是1MB。分配给Slab之后根据slab的大小切分成chunk。

Chunk:用于缓存记录的内存空间。

Slab Class:特定大小的chunk的组。

memcached根据收到的数据的大小,选择最适合数据大小的slab。

memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk,然后将数据缓存于其中。

  • 在Slab中缓存记录的原理

   下面说明memcached如何针对客户端发送的数据选择slab并缓存到chunk中。memcached根据收到的数据的大小,选择最适合数据大小的slab。 memcached中保存着slab内空闲chunk的列表,根据该列表选择chunk, 然后将数据缓存于其中。如下图,

wKiom1YEAu3DWwXkAACkFsS15lE320.jpg

实际上,Slab Allocator也是有利也有弊。下面介绍一下它的缺点。

  • Slab Allocator的缺点

   Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。 例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。如下图,

wKiom1YEAzDAIeCAAABTduV9bDU342.jpg

       对于该问题目前还没有完美的解决方案,但在文档中记载了比较有效的解决方案。就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下, 只要使用适合数据大小的组的列表,就可以减少浪费。但是很遗憾,现在还不能进行任何调优,只能期待以后的版本了。 但是,我们可以调节slab class的大小的差别。 接下来说明growth factor(增长系数)选项。

  • 使用Growth Factor进行调优

   memcached在启动时指定 Growth Factor因子(通过 -f 选项), 就可以在某种程度上控制slab之间的差异。默认值为1.25。 但是,在该选项出现之前,这个因子曾经固定为2,称为“powers of 2”策略。

让我们用以前的设置,以verbose模式启动memcached试试看:

[root@memcache ~]# memcached -f 2 -vv
下面是启动后的verbose输出:
slab class   1: chunk size    128 perslab  8192
slab class   2: chunk size    256 perslab  4096
slab class   3: chunk size    512 perslab  2048
slab class   4: chunk size   1024 perslab  1024
slab class   5: chunk size   2048 perslab   512
slab class   6: chunk size   4096 perslab   256
slab class   7: chunk size   8192 perslab   128
slab class   8: chunk size  16384 perslab    64
slab class   9: chunk size  32768 perslab    32
slab class  10: chunk size  65536 perslab    16
slab class  11: chunk size 131072 perslab     8
slab class  12: chunk size 262144 perslab     4
slab class  13: chunk size 524288 perslab     2

   可见,从128字节的组开始,组的大小依次增大为原来的2倍。 这样设置的问题是,slab之间的差别比较大,有些情况下就相当浪费内存。 因此,为尽量减少内存浪费,追加了growth factor这个选项。来看看现在的默认设置(f=1.25)时的输出:

slab class   1: chunk size     88 perslab 11915
slab class   2: chunk size    112 perslab  9362
slab class   3: chunk size    144 perslab  7281
slab class   4: chunk size    184 perslab  5698
slab class   5: chunk size    232 perslab  4519
slab class   6: chunk size    296 perslab  3542
slab class   7: chunk size    376 perslab  2788
slab class   8: chunk size    472 perslab  2221
slab class   9: chunk size    592 perslab  1771
slab class  10: chunk size    744 perslab  1409

   可见,组间差距比因子为2时小得多,更适合缓存几百字节的记录。 从上面的输出结果来看,可能会觉得有些计算误差, 这些误差是为了保持字节数的对齐而故意设置的。将memcached引入产品,或是直接使用默认值进行部署时, 最好是重新计算一下数据的预期平均长度,调整growth factor, 以获得最恰当的设置。内存是珍贵的资源,浪费就太可惜了。

5、memcached 过期方式

数据过期方式:Lazy Expiration + LRU

  • Lazy Expirationmemcached内部不会监视记录是否过期,而是在get时查看记录的时间戳,检查记录是否过期。这种技术被称为lazy(惰性)expiration。因此,memcached不会在过期监视上耗费CPU时间。

  • LRUmemcached会优先使用已超时的记录的空间,但即使如此,也会发生追加新记录时空间不足的情况,此时就要使用名为 Least Recently Used(LRU)机制来分配空间。当memcached的内存空间不足时(无法从slab class 获取到新的空间时),就从最近未被使用的记录中搜索,并将其空间分配给新的记录。

6、memcached 不互相通信的分布式

   memcached尽管是“分布式”缓存服务器,但服务器端并没有分布式功能。 各个memcached不会互相通信以共享信息。那么,怎样进行分布式呢? 这完全取决于客户端的实现。如下图,

wKioL1YEA1iSSvIsAAC_qVYp8cA588.jpg

7、memcached 支持的平台

  • Linux 

  • FreeBSD 

  • Solaris (memcached 1.2.5以上版本) 

  • Mac OS X 

  • 另外也能安装在Windows上。 


二、memcached 安装与配置

1、安装libevent

[root@hpf-linux ~]# tar -xf libevent-2.0.22-stable.tar.gz 
[root@hpf-linux ~]# cd libevent-2.0.22-stable
[root@hpf-linux libevent-2.0.22-stable]# ./configure --prefix=/usr/local/libevent
[root@hpf-linux libevent-2.0.22-stable]# make && make install

2、安装memcached

[root@hpf-linux ~]# tar -xf memcached-1.4.24.tar.gz 
[root@hpf-linux ~]# cd memcached-1.4.24
[root@hpf-linux memcached-1.4.24]# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent
[root@hpf-linux memcached-1.4.24]# make && make install

3、配置环境变量

[root@hpf-linux memcached-1.4.24]# vim /etc/profile.d/memcached.sh
export PATH=$PATH:/usr/local/memcached/bin/  
[root@hpf-linux memcached-1.4.24]# source /etc/profile.d/memcached.sh

4、memcached 启动选项

  • -p TCP监听端口 (default: 11211) 

  • -U UDP 监听端口 (default: 11211, 0 is off) 

  • -s UNIX socket监听路径,不支持网络 

  • -a UNIX socket访问掩码, 八进制 (default: 0700) 

  • -l 监听的服务器IP地址 (default: all addresses) 

  • -d 启动一个守护进程 

  • -r 最大限度利用核心文件限制 

  • -u 运行memcached用户 

  • -m 最大的内存使用 (default: 64 MB) 

  • -M 内存耗尽返回错误 

  • -c 最大并发连接 (default: 1024) 

  • -k 锁定所有分页内存 

  • -v 输出警告和错误信息 

  • -vv 同时打印客户端请求和返回信息 

  • -vvv 打印内部状态转换信息 

  • -i 打印memcached 和 libevent 版本信息 

  • -P 设置保存pid文件, only used with -d option 

  • -f 块大小增长倍数 (default: 1.25) 

  • -n key+value+flags最小分配空间(default: 48) 

  • -L 如何有效,尝试使用大内存页。增加内存页大小可以减少失误的TLB数量,提高性能。 

  • -D 指定key和IDs的分隔符 default is “:” (colon). 如果指定此选项,统计信息收集自动开启; 

  • -t 使用的线程数量 (default: 4) 

  • -R 每个事件的最大请求数 (default: 20) 

  • -C 禁止使用 CAS 

  • -b 设置积压队列数限制 (default: 1024)、 

  • -B 绑定协议 �C one of ascii, binary, or auto (default) 

  • -I 分配给每个slab页(default: 1mb, min: 1k, max: 128m) 

  • -o 配置额外选项

5、启动memcached

[root@hpf-linux ~]# useradd -r -u 490 -s /sbin/nologin memcached
[root@hpf-linux ~]# memcached -d -m 64 -u memcached -l 192.168.1.6 -c 256 -P /tmp/memcached.pid -vvv

6、查看监听的端口

[root@hpf-linux ~]# ss -tunlp |grep memcached
udp    UNCONN     0      0            192.168.1.6:11211                 *:*      users:(("memcached",18379,27),("memcached",18379,28),("memcached",18379,29),("memcached",18379,30))
tcp    LISTEN     0      128          192.168.1.6:11211                 *:*      users:(("memcached",18379,26))

7、配置SysV脚本

提供配置文件:

[root@hpf-linux ~]# vim /etc/sysconfig/memcached
PORT="11211"
USER="memcached"
MAXCONN="1024"  
CACHESIZE="128"  
OPTIONS=""
[root@hpf-linux ~]# vim /etc/init.d/memcached
#!/bin/bash  
#  
# Init file for memcached  
#  
# chkconfig: - 86 14  
# description: Distributed memory caching daemon  
#  
# processname: memcached  
# config: /etc/sysconfig/memcached
. /etc/rc.d/init.d/functions
## Default variables
PORT="11211"  
USER="memcached"  
MAXCONN="1024"  
CACHESIZE="64"  
OPTIONS=""
[ -f /etc/sysconfig/memcached ] && . /etc/sysconfig/memcached
RETVAL=0
prog="/usr/local/memcached/bin/memcached"  
desc="Distributed memory caching"  
lockfile="/var/lock/subsys/memcached"
start() {
        echo -n $"Starting $desc (memcached): "  
        daemon $prog -d -p $PORT -u $USER -c $MAXCONN -m $CACHESIZE  $OPTIONS  
        RETVAL=$?  
        echo  
        [ $RETVAL -eq 0 ] && touch $lockfile  
        return $RETVAL  
}
stop() {
        echo -n $"Shutting down $desc (memcached): "  
        killproc $prog  
        RETVAL=$?  
        echo  
        [ $RETVAL -eq 0 ] && rm -f $lockfile  
        return $RETVAL  
}
restart() {
        stop  
        start  
}
reload() {
        echo -n $"Reloading $desc ($prog): "  
        killproc $prog -HUP  
        RETVAL=$?  
        echo  
        return $RETVAL  
}
case "$1" in
  start)  
        start  
        ;;  
  stop)  
        stop  
        ;;  
  restart)  
        restart  
        ;;  
  condrestart)  
        [ -e $lockfile ] && restart  
        RETVAL=$?  
        ;;    
  reload)  
        reload  
        ;;  
  status)  
        status $prog  
        RETVAL=$?  
        ;;  
   *)  
        echo $"Usage: $0 {start|stop|restart|condrestart|status}"  
        RETVAL=1  
esac
[root@hpf-linux ~]# chmod +x /etc/init.d/memcached
[root@hpf-linux ~]# chkconfig --add memcached
[root@hpf-linux ~]# chkconfig memcached on

8、启动服务

[root@hpf-linux ~]# service memcached start
Starting Distributed memory caching (memcached):           [确定]

9、测试

[root@hpf-linux ~]# telnet 192.168.1.6 11211
Trying 192.168.1.6...
Connected to 192.168.1.6.
Escape character is '^]'.
stats
STAT pid 8279 #进程ID
STAT uptime 8000 #服务器运行秒数
STAT time 1378284623 #服务器当前unix时间戳
STAT version 1.4.15 #服务器版本
STAT libevent 2.0.21-stable #libevent版本号
STAT pointer_size 64 #操作系统指针大小(这台服务器是64位的)
STAT rusage_user 0.000999 #进程累计用户时间
STAT rusage_system 0.003999 #进程累计系统时间
STAT curr_connections 10 #当前打开连接数
STAT total_connections 11 #曾打开的连接总数
STAT connection_structures 11 #服务器分配的连接结构数
STAT reserved_fds 20 #内部使用的FD数
STAT cmd_get 0 #执行get命令总数
STAT cmd_set 0 #执行set命令总数
STAT cmd_flush 0 #执行flush命令总数
STAT cmd_touch 0 #执行touch命令总数
STAT get_hits 0 #get命中次数
STAT get_misses 0 #get未命中次数
STAT delete_misses 0 #delete未命中次数
STAT delete_hits 0 #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 7 #读取字节总数
STAT bytes_written 0 #写入字节总数
STAT limit_maxbytes 134217728 #现在的内存大小为128M  
STAT accepting_conns 1 #目前接受的新接数
STAT listen_disabled_num 0 #失效的监听数
STAT threads 4 #当前线程数
STAT conn_yields 0 #连接操作主支放弃数目
STAT hash_power_level 16 #hash等级
STAT hash_bytes 524288 #当前hash表等级
STAT hash_is_expanding 0 #hash表扩展大小
STAT bytes 0 #当前存储占用的字节数
STAT curr_items 0 #当前存储数据总数
STAT total_items 0 #启动以来存储的数据总数
STAT expired_unfetched 0 #已过期但未获取的对象数目
STAT evicted_unfetched 0 #已驱逐但未获取的对象数目
STAT evictions 0 #LRU释放的对象数目
STAT reclaimed 0 #用已过期的数据条目来存储新数据的数目
END


三、memcached 使用详解

1、memcached 基本命令

Memcached提供了为数不多的几个命令来完成与服务器端的交互,这些命令基于memcached的协议实现。

  • 存储类命令:set, add, replace, append, prepend 

  • 获取数据类命令:get, delete, incr/decr 

  • 统计类命令:stats, stats items, stats slabs, stats sizes 

  • 清理命令: flush_all 

2、memcached 存储命令的格式

格式:

<command name> <key> <flags> <exptime> <bytes><data block>

参数说明:

  • <command name> 操作命令:set/add/replace…… 

  • <key> 缓存的键值 

  • <flags> 客户机使用它存储关于键值对的额外信息 

  • <exptime> 缓存过期时间 单位为秒 0 表示永远存储 

  • <bytes> 缓存值的字节数 

  • <data block> 数据块 

你可能感兴趣的:(memcached,数据缓存服务器)