一、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应用的速度、 提高可扩展性。如下图:
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
结构图如下:
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, 然后将数据缓存于其中。如下图,
实际上,Slab Allocator也是有利也有弊。下面介绍一下它的缺点。
Slab Allocator的缺点
Slab Allocator解决了当初的内存碎片问题,但新的机制也给memcached带来了新的问题。这个问题就是,由于分配的是特定长度的内存,因此无法有效利用分配的内存。 例如,将100字节的数据缓存到128字节的chunk中,剩余的28字节就浪费了。如下图,
对于该问题目前还没有完美的解决方案,但在文档中记载了比较有效的解决方案。就是说,如果预先知道客户端发送的数据的公用大小,或者仅缓存大小相同的数据的情况下, 只要使用适合数据大小的组的列表,就可以减少浪费。但是很遗憾,现在还不能进行任何调优,只能期待以后的版本了。 但是,我们可以调节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不会互相通信以共享信息。那么,怎样进行分布式呢? 这完全取决于客户端的实现。如下图,
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> 数据块