Linux运维 第三阶段 (十七) memcached
一、相关概念:
memcached.org(live journal站点贡献的),很多流行站点都在用,如wikipedia、twitter、youtube、mixi等,memcached是非常流行的缓存服务,众多的应用程序开发基本都支持memcached缓存(C有C库,C++有C++库,php有php库,开发时都可直接调用memcached功能,若某个应用程序开发时不用memcached,它就不能往memcached中缓存数据,缓存数据与否取决于app自身,由app决定缓不缓存用不用它)
memcached(键值对key:value server),它只适合存储key:value的数据,而且是缓存cache不是存储store(mysql是store,数据存储下来关机是没事的)
若将http中的web object缓存到memcached中,相应的key应如何存,每个web object都通过uri获取,如http://www.magedu.com/index.html,这个web object是唯一的,就将这个uri(index.html)当作key,而文件中的内容作为value
memcached是C/S架构的程序,tcp|udp(tcp支持长连接,每次从缓存中获取数据要三次握手很浪费时间;若server对性能要求高使用udp),无论tcp|udp都要基于IP报文发送,memcached会监听在某个socket上,否则无法接收client请求
tcp|udp,port:11211,由libevent提供event-driven功能的库文件
ftp service、httpd service之间区别(client同server端交互):
协议的不同获取资源的方式不一样;使用独有的协议实现client和server的交互;
client发命令过去,server要接收并理解这个命令并做出处理,例如http报文,client(GET+URI),server理解GET并将资源响应给client,或client(PUT+FILE),server端先接收指令PUT并将文件存储下来;这些PUT、GET就是操作命令,例如ftp中的操作命令(put、get、mput、mget等);
ftp和http这些协议所使用的命令都很简单,基于文件命令的简单协议simple protocol(http:text;ftp:text,binary),若想使用复杂命令(例如用get获取server上某个文件而且要查询文件对应的时间是否正确,否则就不要)是不能达到这样的要求的
memcached上client和server的交互就是上面这种方式(simplep rotocol),整个处理机制非常简单,在其协议的实施上默认也是基于simple protocol,封装任何指令不使用xml格式
注:两台计算机之间为了交互数据,为能让对方更能理解请求的命令是什么,使用xml格式封装指令,如集群,大多数配置文件是xml格式的,就为实现某些数据交互,避免对方误解,这种协议它所支持的功能及配置非常强大,但xml本身要能解析xml的文档,任何一个协议若支持xml格式传输数据的话,那client和server都要有一个xml引擎,至少要能分析xml文档,这将导致server复杂,而memcached本身就是为了高性能而存在的,所以越简单越好,因此memcached仅支持一些简单的命令,如get(获取一个key对应的value)、set(设定,保存缓存)
作为memcached,往它上面存key:value的数据,编码格式:
text,使用文本格式,整个处理机制将简单很多,还可用#telnet localhost 11211进行测试;
binary,二进制格式,在安全性、效率上要好得多,使用这种格式就要用到专用客户端工具,例如ftp client工具(既支持text又支持binary,如果默认是binary就只能使用专用客户端工具),只有客户端工具才能理解传输的内容,封装数据并传输,接收数据并还原
memcached早期使用text方式(基于text发送指令),现在支持两种格式(text|binary,发送指令,实现数据的上传(将数据放入缓存)下载(从缓存获取数据))
memcached是一个缓存服务器,但本身无法决定缓存任何数据,这意味着一半依赖于client-side,一半依赖于server-side,存储是由memacached server负责并提供检索能力,至于怎么存储、存多长时间(过期时间)、谁来存储是由client决定的(client要自己提供key名,标志位、缓存时长、value)
例如:set key 5 6 hello
memcached缓存管理工作在lazy模型下(只要系统上有足够空间可用,无论缓存数据有无过期都不会清理,只有没空间使用的情形下才清理),惰性的清理机制,同时又是LRU的清理机制(last recently use,最近最少使用)
若缓存空间过小,但缓存的数据量很大,这样导致缓存抖动很厉害(存了清,清了存,很少命中)
由于存了很多数据,因管理不善或空间过小,导致雪崩效果(表现为缓存数据很多,但就是命中不了)
memcached既然是缓存服务器,它并不保证数据持久存储(它假设自己坏了无所谓,它坏了,除影响业务本身访问速度变慢外,是不影响数据本身的),它尽可能实现用内存来缓存数据(内存缓存server),单个对象大小(下限48byte,上限1M)
memcached在内存中是如何管理缓存的数据,为了存储数据对象,要在内存开辟一段区域(内存中的数据都是按字节序列化的),一个byte一个byte的存,每一个byte都是编址的单元,使用时是按页来用,要能在内存中标记起始地址和结束地址,若失效这段空间要腾出来,这样存储大小不一的对象,存一个删一个,时间久了会有碎片,内存中到处是缝隙,缝隙多了内存要高效利用将很困难(如存一个数据,半天找不到空闲的地方),要反复的完成内存的申请、释放,尤其当存储百万个缓存对象时,这种建立、释放本身要消耗大量的时间,内存碎片将导致进程运行起来会非常慢,刚开始问题不大,运行越久越会拖慢速度,而我们用memcached是用来加速的
对于以上问题,如何用高效的机制解决内存的建立和释放,linux内核有两种机制来管理避免内存碎片(buddy system伙伴系统;slab allocator,slab分配器)
buddy system(避免内存外碎片,它实现在整个内存当中以页面的方式管理内存时,有足够的连续的空间可用;在x86或x86_64的server上,通常是4K大小一个页面,这就意味着,一个进程存第一个对象时,若这个对象8K要用2个页面,这个对象16K要用到4个页面,这样时间长了会有内存页碎片,若之后需要10M的连续空间,由于内存全是缝隙将找不到,为避免这种情况,buddy system就是解决将临近的空闲的内存页面合并为一个大的连续空间,将来申请时可以从一头开始,而不用从中间申请,这将避免页碎片)
注:有些数据存储时占用不了一个页面,例如内核在打开文件时,每一个inode结构(包括inode及元数据各种属性)仅占128byte左右的空间,若直接使用一个页面存那就太浪费空间了,使用slab allocator解决
slab allocator(避免内存内碎片,将要存储数据的大小小于页面单位的(非常小的内存数据结构),给它事先分配好这些结构,随时等待有需求的进程或要存储的对象使用,而且使用结束后不再销毁,随时重复利用,若不够用时再找一个空闲页面立即划分好,这样在使用时不用申请直接用已划分好的;OS上有众多的数据结构都需要这种方式实现,而且存储空间大小也各不相同,如每个进程都有进程描述符(进程号、进程名、属主、属组等信息)空间占约256byte、打开文件时的inode结构占约128byte,这样slab allocator为每一种数据结构都准备一些空间在那放着,任何时候申请直接使用已划分好的,用完后重新放在可用列表中(归类到空闲列表中),所以slab allocator将整个内存中的数据结构分成了已用的和空闲的,在内核中它使用一个数据结构追踪某个slab对象占据的有几个页面(大对象可分多个页面,小对象在一个页面中再次划分),哪个页面是空闲的,依次第一个页面用完了再用第二个,若之后第一个有空闲就在第一个上放数据,达到重复利用的目的
一旦给memcached指定有多大内存空间可用后,它会在可用的物理内存空间中申请过来,并且划分好存储空间,分好一个个的slab chunk,每一次缓存数据,找到最佳slab class,若指定的内存空间存满了就要清理了(根据LRU算法),没有存满就算过期了也不清理(lazy模型)
例如给memcached指定512M内存,服务在启动时会在内存中划分512M区域开始分片,分片时它会考虑到各种数据大小的存储,例如48byte分一堆,80byte的分一堆,200byte的再分一堆,这每一个类别叫slab类(slab class),每一slab class中都有很多块用来存数据,每一块叫slab chunk,之后要存数据,它会找一个最适合的大小的区域单元来存放,这每一类间隔越小则空间的浪费越少(但类别过多管理也会麻烦),例如要存20byte的数据,它会自动找到48byte这个slab class存(虽然它仅占20byte,另28byte空间就浪费了,为使内存高效管理此处浪费不可避免);早期memcached类别之间是呈2倍增长趋势的,这种管理方式粗糙,浪费的空间大,现在支持使用增长因子来定义(growth factor,在每个类别上定义,每次在上次的基础上往上涨多少),增长因子一般是在1和2之间的数,例如有一类是48byte定义growth factor为2,则下一个是96,若growth factor定义为1.1,则下一个是48*1.1
memcached是不通信的分布式缓存服务器(它本身不支持高可用,但分布式功能是它的强项,分布式算法是在app-server上实现的),例如有两台memcached-server,前端app-server若轮流使用memcached,该怎么轮并不取决于这两台memcached-server(这两个memcached彼此间不通信,不需监控对方心跳等),而是用前端的app-server实现(memcached是否在线,上传数据等)
注:若是小规模应用完全可在app-server上实现调度;若大规模,则使用调度器(LVS、nginx、haproxy)加持久连接实现
memcached键值对key:value存储时,如对key做hash运算除以memcached-server总数再取余,就可定位到是用哪台memcached-server存储,这种算法有很大缺陷(弊端),例如若4台memcached中有其中一台挂了或者又新增了一台,之前是除以4,现在除以3,结果导致查询缓存不会定位到之前的那台memcached-server上,所以大量缓存失效要重新建立
consistency hash(一致性哈希算法):client使用,例如一个环中有n个点位(散列的很多挨着的点),这些点0-2^32,有几台memcached-server就将其对应的放在环中的某个点上(例如有4台,2^32除以4),缓存数据时,仍取离散的值,对key做hash运算除以2^32取余,这个值会分散在环中某个点上,按顺时针找最近的一台server存储要缓存的数据,若某一server挂了或增加了一台,则只影响环中某一段中的缓存(增加或减少server只影响局部,之前的算法会影响到全部),使用这种算法将影响范围降到最低
以下是在LNMP架构中提到的memcached:
memcached(两个功能:实现缓存后端DB-server的查询结果,提供给多个app-server使用;缓存app-server的session信息):
它本身只是个提供缓存功能的server,到底缓不缓存,谁来缓存,怎么缓存,缓存过期时间,缓存清除等它自身不管,它可以根据你的请求,替你做出决策,例如,app-server查询DB,觉的这个结果可以缓存,由app-server自己把数据放至memcaced 上,当app-server下次找数据时就自动去memcached上去找,memcached是个公共缓存,可被多个node共同使用,若命中率达到40%,对系统性能的提升非常明显
若是电商站点,后端某个app-server挂了,每一个app-server为了维持某个用户的购物车、http等会话信息会结合cookie在app-server本地内存中要维护一个session,每一个client只要连接,在app-server上都有session信息,若某个用户第一次连接在app-server5上,第二次被分配到了app-server1上,那之前的会话信息就没了,为使会话继续使用,可用持久连接(同一client的请求始终定位至同一个app-server上,虽会破坏LB效果,但能实现),但要是app-server5挂掉,用户一刷新同样会定位到其它app-server上,会话也照样没了,如果用户请求有5万个,某一个app-server挂掉将会丢失1万个session信息(很可怕)
注:session信息是保存在当前某一个app-server上的本地内存中一份,而且在FS上也会保存一份,方便以后读取,所以只能被这一个主机所使用
如果app-server建成集群,session信息在内存中可完成同步,如用户请求app-server1,app-server1在建立会话以后,直接通过高可用集群同步至任一node的内存中去,这将有额外的开销(每一个app-server都要通过组播发送出去),若app-server很多每一次这样同步数据量会很大,在小规模场景中勉强可用,但大规模场景就不理想了
这时要在各app-server间共享session,使用一个公共区域来保存session信息,让每一个app-server都到这个公共区域中去读会话信息,memcached正是这么一个公共缓存
当某一用户请求第一次被发到app-server1上时,app-server1发现需要为这个请求建立会话,这个会话数据不再保存在本地,直接保存到memcached中,之后哪怕这个用户的请求被转至app-server2上,app-server2会根据用户的cookie信息自动地去memcached中找session信息,把session读过来与用户建立会话,于是本地就有,不过这时风险更大,若memcached挂了,那所有会话都没了,想到为memcached做高可用,memcached本身并不支持高可用,但若做成高可用了也并不理想(它会这样假设,你保存在我这的都是缓存数据,是非关键性数据,是读取的原始数据,我这里的数据就算丢了,你无非是重建而已,我这里不会使用高可用的),但它可很好的实现分布式的功能(memcached的强项),这就意味着1个memcached不够用可用多个memcached,如有3个memcached,app-server在存数据时会选一个来存,查找时通过某种算法(例如将用户的cookie作hash运算再除以3取余,hash运算的结果相同除3取余的结果就相同)再定位至这个memcached-server上
注:若把memcached做成HA-server,意义并不大也不理想(因为缓存数据是在内存中,除非解决两个进程间通过内存将某一node的缓存通知给另一node)
这样memcached不仅可以缓存DB中查询的数据,还能缓存session信息,所以有人把memcached称万金油(银蛋),它能应付各种情况和场景,只要数据可缓存且缓存的是可序列化的数据(如string、各object等,网络上传输的是01代码,若发一张图片或其它对象最终都可被抽成一根线,再通过网络发送,接收端接收下来将其合并并还原即可)它都能缓存下来,不能序列化就无法在内存中存储,就更不用说发送了
缓存方法就是在内存中开辟一段很小的区域,每个缓存对象将占用一个小区域将数据缓存下来
若缓存了有1KW个数据,之后要怎么找,若要遍历这1000W个对象那也太慢了,memcached是键值存储(key:value),在存储时首先给这个数据创建个查找键key,然后再存储它的值value,key:value存储通常都是基于hash方式,每存一个数据时这个key也需要地方存储,key存储在叫做hash bucket桶中(hash bucket有多个),key存在哪一桶个中是根据hash函数计算得出的,每个桶中比如规定只存100个key,将来要找某一个key时做hash运算(hash函数),运算完后就知道在哪个hash bucket中,找到这个桶后,桶中数据相对就很少了,在hash bucket中迅速的做下字符串比较(二次计算)立即找出键,基于这种方式查找速度是无与伦比的快(hash索引非常快,所以查找都是O(1)的),这样1000个键无非是在某个桶中找一次,1000万个键无非是找出在哪一个桶中
但存储太多个对象也不好,每存储一个数据都要开辟一小段内存,不同的场景所需要的空间也不一样,对象多了导致内存碎片化,在内存中的这些对象要被管理(如对象过期要回收等),要有很好的内存管理策略(策略即算法,通过程序不定期的去执行,执行就要消耗CPU时间,会有额外开销),当对象少时没什么问题,但对象超多,内存随时都要释放和回收、分配,这是不小的工作量,所以并不建议在memcached中缓存过多的数据
memcached缓存时支持的单个对象最大1M空间,最小48byte
memcache是C/S架构,client就是app-server,应用程序通过协议把数据通过网络传送给memcached-server,memcached根据client的请求将数据缓存下来,所以client可向server-side发送不同指令,如建立缓存、清除缓存、在缓存中附加新数据等有很多命令
二、操作(1、memcached安装;2、常用命令;3、安装php的扩展memcache;4、nginx整合memcached;5、php的session保存在memcached中;6、使用web界面管理工具memadmin):
环境:
[root@node1 ~]# uname -a
Linux node1.magedu.com 2.6.32-358.el6.x86_64#1 SMP Tue Jan 29 11:47:41 EST 2013 x86_64 x86_64 x86_64 GNU/Linux
准备安装包及yum源:
libevent-2.0.22-stable.tar.gz
memcached-1.4.25.tar.gz
memcache-2.2.7.tgz
memadmin-1.0.12.tar.gz
注:在LNMP环境上操作(LNMP环境搭建参照《Linux运维第三阶段(十五)理解LNMP》
1、安装
[root@node1 ~]# yum -y groupinstall “Desktop Platform” “Desktop Platform Development” "Server Platform Development" “Development tools” “Compatibility libraries”(确保这几个底层依赖包已安装)
[root@node1 ~]# rpm -q libevent(此版本在memcached源码编译时过不去,得安装2.0.22版本,2.0比自带的glibc库性能要高很多,对于高并发的程序它们运行时会自动使用libevent库)
libevent-1.4.13-4.el6.x86_64
[root@node1 ~]# rpm -q cyrus-sasl-devel(认证相关,确保已安装)
cyrus-sasl-devel-2.1.23-13.el6_3.1.x86_64
[root@node1 ~]# tar xf libevent-2.0.22-stable.tar.gz
[root@node1 ~]# cd libevent-2.0.22-stable
[root@node1 libevent-2.0.22-stable]#./configure --prefix=/usr/local/libevent
[root@node1 libevent-2.0.22-stable]# make && make install
[root@node1 libevent-2.0.22-stable]# cd
[root@node1 ~]# echo "/usr/local/libevent/lib" > /etc/ld.so.conf.d/libevent.conf
[root@node1 ~]# ldconfig -v
[root@node1 ~]# ln -sv /usr/local/libevent/include/ /usr/include/libevent
"/usr/include/libevent" ->"/usr/local/libevent/include/"
[root@node1 ~]# tar xf memcached-1.4.25.tar.gz
[root@node1 ~]# cd memcached-1.4.25
[root@node1 memcached-1.4.25]# ./configure --help
[root@node1 memcached-1.4.25]# ./configure --prefix=/usr/local/memcached --enable-sasl --with-libevent=/usr/local/libevent
[root@node1 memcached-1.4.25]# make && make install
[root@node1 memcached-1.4.25]# cd /usr/local/memcached/
[root@node1 memcached]# ls bin
memcached
[root@node1 memcached]# echo "export PATH=$PATH:/usr/local/memcached/bin/" > /etc/profile.d/memcached.sh
[root@node1 memcached]# . !$
. /etc/profile.d/memcached.sh
[root@node1 memcached]# cd
[root@node1 ~]# memcached -h(类似mysql-proxy,支持很多选项)
-m NUM(以M为单位指定最大可用内存空间,max memory to use for items in megabytes (default: 64 MB))
-n BYTES(指定最小存储块是多大slab chunk,增长因子就是在此基础上增加的,minimum space allocated for key+value+flags (default: 48))
-f FACTOR_NUM(指定增长因子grown factor,一般1-2之间的数,chunk size growth factor (default: 1.25))
-vv(very verbose (also print client commands/reponses))
-u USERNAME(assume identity of <username> (only when run as root))
-d(run as a daemon)
-p NUM(TCP port number to listen on (default: 11211))
-U NUM(UDP port number to listen on (default: 11211, 0 is off))
-l ADDRESS(interface to listen on (default: INADDR_ANY, all addresses))
-S(启用sasl认证,Turn on Sasl authentication)
-s FILE(指定socket,类似mysql中/tmp/mysql.sock本地套接字的通信机制,能利用近似共享内存的方式通信,UNIX socket path to listen on (disables network support))
-r(maximize core file limit)
-c NUM(最大并发连接数,max simultaneous connections (default: 1024))
-t NUM(用于处理入站请求的最大线程数,仅在memcached编译时开启支持线程才有效(linux对线程支持有限),number of threads to use (default: 4))
-P FILE(save PID in <file>, only used with -d option)
-L(试图使用最多的内存空间,Try touse large memory pages (if available))
-C(Disable use of CAS)
-b NUM(Set the backlog queue limit (default: 1024))
-o(指定额外选项,Comma separated list of extended or experimental options)
[root@node1 ~]# memcached -m 64 -n 20 -f 1.1 -vv -u nobody -d(可看出具体分配空间过程)
[root@node1 ~]# slab class 1: chunk size 72 perslab 14563
slab class 2: chunk size 80perslab 13107
slab class 3: chunk size 88perslab 11915
slab class 4: chunk size 96perslab 10922
slab class 5: chunk size 112perslab 9362
slab class 6: chunk size 128perslab 8192
slab class 7: chunk size 144perslab 7281
slab class 8: chunk size 160 perslab 6553
……
[root@node1 ~]# netstat -tnupl | grep :11211
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 3957/memcached
tcp 0 0 :::11211 :::* LISTEN 3957/memcached
udp 0 0 0.0.0.0:11211 0.0.0.0:* 3957/memcached
udp 0 0 :::11211 :::* 3957/memcached
[root@node1 ~]# killall memcached
[root@node1 ~]# ps aux |grep memcached |grep -v grep
[root@node1 ~]# vim /etc/init.d/memcached(为memcached提供sysv风格启动脚本,此脚本内容见文末附)
[root@node1 ~]# vim /etc/sysconfig/memcached(并为脚本提供配置文件,方便各配置选项的更改)
CACHESIZE="64"
BYTES="48"
FACTOR="1.25"
USER="nobody"
PORT="11211"
MAXCONN="1024"
OPTIONS=""
[root@node1 ~]# chmod +x !$
chmod +x /etc/init.d/memcached
[root@node1 ~]# chkconfig --add memcached
[root@node1 ~]# service memcached start
Starting Distributed memory caching(memcached): [确定]
2、常用命令:
memcached支持的命令(在telnet下使用,因为memcached没有客户端工具,只能在telnet下直接交互):
syntax格式:
COMMAND_NAME KEY_NAME FLAGS EXPIRE_TIME BYTES
DATA_BLOCK
其中COMMAND_NAME常用的有(set|get|gets|add|replace|delete|cas|stats|statsitems|append|prepend|flush_all|incr|decr);
KEY_NAME(要知道某个key所对应的value值,必须要知道key_name)
FLAGS(客户机使用此项存储关于key:value的额外信息)
EXPIRE_TIME(过期时间,0表示永远不过期)
BYTES(存储字节数)
DATA_BLOCK(存放value)
[root@node1 ~]# telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
stats(输入此指令可看相关状态)
STAT pid 3957
STAT uptime 255
STAT time 1448113877
STAT version 1.4.25
STAT libevent 2.0.22-stable
STAT pointer_size 64
……
STAT get_hits 0
STAT get_misses 0
STAT delete_misses 0
STAT delete_hits 0
set mykey 0 10 12(set使用频率很高,用于如果key不存在,使用set可添加,如果key存在,使用set可更新key相关数据)
hello magedu
STORED
get mykey(get后跟key_name,查看key所对应的value,若要查看多个key用空格隔开)
VALUE mykey 0 12
hello magedu
END
add mykey1 0 0 7(add添加,仅在key不存在时才能添加)
jowin
STORED
get mykey1
VALUE mykey1 0 7
jowin
END
set mykey1 0 0 8(set更新key所对应的参数及value)
chai
STORED
get mykey1
VALUE mykey1 0 8
chai
END
replace mykey1 0 0 8(replace替换,仅在key存在时才能使用)
cjowin
STORED
get mykey1
VALUE mykey1 0 8
cjowin
END
delete mykey1(删除,已存在记录和不存在的记录会返回不同的结果)
DELETED
delete mykey2
NOT_FOUND
add mykey 0 0 7
hello
STORED
gets mykey(gets返回结果比get返回的结果多了一列,最后一列这个数字(此例中是7)可检查数据是否发生改变,当key对应的value改变时,最后的这个数字也会变化)
VALUE mykey 0 7 7
hello
END
replace mykey 0 0 7
haha
STORED
gets mykey(内容改变时,gets得到的结果中最后一个数字也变了)
VALUE mykey 0 7 8
haha
END
cas mykey 0 0 7 8(cas,checked and set,只有在此处输入的最后一个数字与gets得到的最后一位数字相同才存储,否则返回exists)
hello
STORED
gets mykey
VALUE mykey 0 7 9
hello
END
cas mykey 0 0 7 18
kao
EXISTS
stats items(列出STAT itmes行,若memcached中存储内容很多会列出很多行)
STAT items:2:number 1
STAT items:2:age 173
STAT items:2:evicted 0
STAT items:2:evicted_nonzero 0
STAT items:2:evicted_time 0
STAT items:2:outofmemory 0
STAT items:2:tailrepairs 0
STAT items:2:reclaimed 0
STAT items:2:expired_unfetched 0
STAT items:2:evicted_unfetched 0
STAT items:2:crawler_reclaimed 0
STAT items:2:crawler_items_checked 0
STAT items:2:lrutail_reflocked 0
END
stats cachedump 2 0(2是stats item返回的值,表示slab_id;0表示limit_num代表返回所有记录数;通过stats items,stats cachedump slab_id limit_num,get可遍历memcached的记录)
ITEM mykey [7 b; 1448113562 s]
END
stats cachedump 2 128
ITEM mykey [7 b; 1448113562 s]
END
另还有常用的:stats slabs,stats sizes,stats reset
append(在现有缓存数据后添加缓存数据);prepend(在现有的缓存数据前添加缓存数据);flush_all(默认使已经存在的key:value立即失效,或在指定的时间后,执行这个命令后再用get获取key时将不会有内容返回,之前的key:value在内存中并没有释放(因为是lazy模型及LRU清理机制))
3、安装php扩展(memcache):
使用某一应用程序(php或mysql)来连接一个服务(memcached或mysqld)时,必须要利用这个服务的客户端库来编程(例如mysql用自己的client连上服务直接发命令,在使用php编程时调用一个库mysql-connect,在函数中传一大堆参数),没法直接调用客户端,只能用客户端库,这就是很多应用程序要提供命令行工具(供用户测试使用)和库(库可供二次开发用)
memcached没有客户端,只是通过#telnet localhost 11211与服务直接交互,作为php程序员(或C程序员)在开发时,要写一个程序能够利用memcached服务器来完成数据缓存以此提高系统性能,必须要针对客户端库来编程,由此必须要为某一种语言提供客户端库,以完成这个程序编程时尽可能简单的利用memcached
客户端库有(三种语言perl、php、C/C++各自提供的客户端库):
perl module(perl要使用memcached就用这个perl module):
cache;;memcached
php(php要使用memcached,得为php安装一个扩展,共提供了两个库(两个扩展)):
memcache
memcached
注:注意这里的memcache和memcached是php的两个库(两个扩展,使用时安装一个即可),memcached比memcache要先进,支持的功能要强大,一般用memcached
C/C++:
libmemcached
[root@node1 ~]# vim /etc/nginx/nginx.conf(确保以下段配置就绪)
……
location / {
root html;
index index.php index.html index.htm;
}
……
location ~ \.php$ {
root html;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name;
include fastcgi_params;
}
……
[root@node1 ~]# cat /usr/html/index.php
<?php
phpinfo();
?>
[root@node1 ~]# service nginx start
正在启动 nginx: [确定]
[root@node1 ~]# service php-fpm start
Starting php-fpm done
[root@node1 ~]# netstat -tnlp | grep :9000
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 4998/php-fpm
[root@node1 ~]# ps aux | grep -v grep |grep -c php-fpm(php-fpm进程共9个,其中1个主进程,8个子进程,在/usr/local/php/etc/php-fpm.conf配置文件中设置了pm.start_servers= 8)
9
[root@node1 ~]# tar xf memcache-2.2.7.tgz
[root@node1 ~]# cd memcache
[root@node1 ~]# cd memcache-2.2.7
[root@node1 memcache-2.2.7]#/usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20100412
Zend Module Api No: 20100525
Zend Extension Api No: 220100525
[root@node1 memcache-2.2.7]# ./configure --with-php-config=/usr/local/php/bin/php-config --enable-memcache
[root@node1 memcache-2.2.7]# make && make install(记录安装完后最后一行给的目录)
……
Installing shared extensions: /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/
[root@node1 memcache-2.2.7]# ls /usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/
memcache.so xcache.so
[root@node1 memcache-2.2.7]# vim /etc/php.d/memcache.ini
extension = “/usr/local/php/lib/php/extensions/no-debug-non-zts-20100525/memcache.so”
[root@node1 memcache-2.2.7]# cd
[root@node1 ~]# vim /usr/html/test.php
---------------test pagestart--------------------
<?php
$mem = new Memcache;
$mem->connect("127.0.0.1",11211) or die("Could notconnect");
$version = $mem->getVersion();
echo "Server's version:".$version."<br/>\n";
$mem->set('testkey', 'hello magedu', 0,600) or die("Failed to save data at the memcached server");
echo "Store data in the cache (datawill expire in 600 seconds)<br/>\n";
$get_result = $mem->get('testkey');
echo "$get_result is from memcachedserver.";
?>
---------------test pageend------------------
[root@node1 ~]# service php-fpm restart
Gracefully shutting down php-fpm . done
Starting php-fpm done
测试:
[root@node1 ~]# telnet localhost 11211
Trying 127.0.0.1...
Connected to localhost.
Escape character is '^]'.
get testkey
VALUE testkey 0 12
hello magedu
END
4、nginx整合memcached
注:nginx的缓存是在磁盘上性能不好
[root@node1 ~]# vim /etc/nginx/nginx.conf
server {
listen 80;
server_name localhost;
root html;
location / {
set $memcached_key $uri;
memcached_pass 127.0.0.1:11211;
default_type text/html;
error_page 404 @fallback;
}
location @fallback {
proxy_pass http://192.168.41.135;
}
}
5、将php的session保存在memcached中:
[root@node1 ~]# vim /etc/php.ini(注意Session段中以下几项,session.name按默认,此名字之后在很多地方要用到)
[Session]
session.save_handler = memcache
session.save_path = "tcp://127.0.0.1:11211?persistent=1&weight=1&timeout=1&retry_interval=15"
session.name = PHPSESSID
测试:准备两个测试脚本
[root@node1 ~]# vim /usr/html/setsession.php
--------------test script start-------------
<?php
session_start();
if (!isset($_SESSION['www.MageEdu.com'])) {
$_SESSION['www.MageEdu.com'] = time();
}
print $_SESSION['www.MageEdu.com'];
print "<br><br>";
print "Session ID: " .session_id();
?>
------------------test script end-------------
[root@node1 ~]# vim /usr/html/showsession.php
---------------test script start--------------
<?php
session_start();
$memcache_obj = new Memcache;
$memcache_obj->connect('127.0.0.1',11211);
$mysess=session_id();
var_dump($memcache_obj->get($mysess));
$memcache_obj->close();
?>
-------------test script end----------------------
6、使用web界面管理工具memadmin:
此工具官网描述:
MemAdmin是一款可视化的Memcached管理与监控工具,基于PHP5&JQuery开发,体积小,操作简单.
MemAdmin主要功能:
服务器参数监控:STATS、SETTINGS、ITEMS、SLABS、SIZES实时刷新
服务器性能监控:GET、DELETE、INCR、DECR、CAS等常用操作命中率实时监控
支持数据遍历,方便对存储内容进行监视支持条件查询,筛选出满足条件的KEY或VALUE 数组、JSON等序列化字符反序列显示
兼容memcache协议的其他服务,如Tokyo Tyrant (遍历功能除外) 支持服务器连接池,多服务器管理切换方便简洁.
[root@node1 ~]# tar xf memadmin-1.0.12.tar.gz
[root@node1 ~]# mv memadmin /usr/html/
[root@node1 ~]# ls /usr/html/memadmin/
apps config.php images include index.php langs LICENSE.txt README.txt views
[root@node1 ~]# vim /usr/html/memadmin/config.php(此文件中有账号密码,默认都是admin)
添加服务器连接-->名称:localhost,host:127.0.0.1,port:11211,持久化连接30秒-->添加-->开始管理
附:memcached启动脚本:
--------------script start-----------------
#!/bin/bash
#
# Init file for memcached
#
# chkconfig: - 86 14
# description: Distributed memory cachingdaemon
#
# processname: memcached
# config: /etc/sysconfig/memcached
. /etc/rc.d/init.d/functions
## Default variables
CACHESIZE="64"
BYTES=”48”
FACTOR=”1.25”
USER="nobody"
PORT="11211"
MAXCONN="1024"
OPTIONS=""
[ -f /etc/sysconfig/memcached ] && source /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 -m $CACHESIZE -n $BYTES -f $FACTOR -u $USER -p $PORT -c$MAXCONN -d
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
exit $RETVAL
--------------scrip tstop--------------------
以上是学习《马哥运维课程》做的笔记。