memcache缓存服务器的搭建

一、MemCache简介

MemCache官方网站
一个自由、源码开放、高性能、分布式的内存对象缓存系统,用于动态Web应用以减轻数据库的负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高了网站访问速度。
MemCache是一个存储键值对的HashMap,在内存中对任意的数据(比如字符串、对象等)使用key-value存储,数据可以来自数据库调用、API调用,或者页面渲染的结果。
设计理念就是小而强大,简单的设计促进了快速部署、易于开发并解决面对大规模的数据缓存的许多难题,而所开放的API使得MemCache能用于Java、C/C++/C#、Perl、Python、PHP、Ruby等大部分语言。
为什么会有Memcache和memcached两种名称?
Memcache是项目的名称,而memcached是它服务器端的主程序文件名。
1.MemCache访问模型
为了加深对memcache的理解,以memcache为代表的分布式缓存,访问模型如下:
在这里插入图片描述
注意:MemCache虽然被称为”分布式缓存”,但是MemCache本身完全不具备分布式的功能,MemCache集群之间不会相互通信(与之形成对比的,比如JBoss Cache,某台服务器有缓存数据更新时,会通知集群中其他机器更新缓存或清除缓存数据)。
所谓的”分布式”,完全依赖于客户端程序的实现,就像上图的流程一样。
基于这张图,MemCache一次写缓存的流程如下:

(1)应用程序输入需要写缓存的数据;

(2)API将Key输入路由算法模块,路由算法根据Key和MemCache集群服务器列表得到一台服务器编号;

(3)由服务器编号得到MemCache及其ip地址和端口号;

(4)API调用通信模块和指定编号的服务器通信,将数据写入该服务器,完成一次分布式缓存的写操作;

读缓存和写缓存一样,只要使用相同的路由算法和服务器列表,只要应用程序查询的是相同的Key,MemCache客户端总是访问相同的客户端去读取数据,只要服务器中还缓存着该数据,就能保证缓存命中。
MemCache集群的方式也是从分区容错性的方面考虑,假如Node2宕机,那么Node2上面存储的数据都不可用了,此时由于集群中Node0和Node1还存在,下一次请求Node2中存储的Key值时,肯定是没有命中的,这时先从数据库中拿到要缓存的数据,然后路由算法模块根据Key值在Node0和Node1中选取一个节点,把对应的数据放进去,这样下次就又可以走缓存了,这种集群的做法很好,但是缺点是成本比较大。
2.算法介绍
从上图中可以看出一个很重要的问题,就是对服务器集群的管理,路由算法至关重要,就和负载均衡算法一样,路由算法决定着究竟该访问集群中的哪台服务器,先看一个简单的路由算法。
(1)余数Hash
简单的路由算法可以使用余数Hash:用服务器数目和缓存数据KEY的hash值相除,余数为服务器列表下标编号,假如某个str对应的HashCode是52、服务器的数目是3,取余数得到1,str对应节点Node1,所以路由算法把str路由到Node1服务器上。由于HashCode随机性比较强,所以使用余数Hash路由算法就可以保证缓存数据在整个MemCache服务器集群中有比较均衡的分布。
如果不考虑服务器集群的伸缩性,那么余数Hash算法几乎可以满足绝大多数的缓存路由需求,但是当分布式缓存集群需要扩容的时候,就难办了。
假设MemCache服务器集群由3台变为4台,更改服务器列表,仍然使用余数Hash,52对4的余数是0,对应Node0,但是str原来是存在Node1上,这就导致了缓存没有命中。
举个例子,原来有HashCode为0~19的20个数据,那么:
在这里插入图片描述
现在扩容到4台,加粗标红的表示命中:
在这里插入图片描述
如果扩容到20+的台数,只有前三个HashCode对应的Key是命中的,也就是15%。当然现实情况肯定比这个复杂得多,不过足以说明,使用余数Hash的路由算法,在扩容时会造成大量的数据无法正确命中(其实不仅仅是无法命中,那些大量的无法命中的数据还在原缓存中在被移除前占据着内存)。在网站业务中,大部分的业务数据度操作请求上事实上是通过缓存获取的,只有少量读操作会访问数据库,因此数据库的负载能力是以有缓存为前提而设计的。当大部分被缓存的数据因为服务器扩容而不能正确读取时,这些数据访问的压力就落在数据库上,这将大大超过数据库的负载能力,严重的可能会导致数据库宕机。
这个问题有解决方案,解决步骤为:

(1)在网站访问量低谷,通常是深夜,技术团队加班,扩容、重启服务器;

(2)通过模拟请求的方式逐渐预热缓存,使缓存服务器中的数据重新分布;

(2)一致性Hash算法
通过一个叫做一致性Hash环的数据结构实现Key到缓存服务器的Hash映射。简单地说,一致性哈希将整个哈希值空间组织成一个虚拟的圆环(这个环被称为一致性Hash环)。
假设某空间哈希函数H的值空间是0~2^32-1(即哈希值是一个32位无符号整形),整个哈希空间如下:
在这里插入图片描述
下一步将各个服务器使用H进行一个哈希计算,具体可以使用服务器的IP地址或者主机名作为关键字,这样每台机器能确定其在上面的哈希环上的位置,并且是按照顺时针排列,这里假设三台节点memcache经计算后位置如下:
在这里插入图片描述
接下来使用相同算法计算出数据的哈希值h,并由此确定数据在此哈希环上的位置。
假如有数据 A、B、C、D、4个对象,经过哈希计算后位置如下:
在这里插入图片描述
根据一致性哈希算法,数据A就被绑定到了server01上,D被绑定到了server02上,B、C在server03上。
按照顺时针找最近服务节点方法这样得到的哈希环调度方法,有很高的容错性和可扩展性。
假设server03宕机
在这里插入图片描述
可以看到此时C、B会受到影响,将B、C节点被重定位到Server01。
一般在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即顺着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。
考虑另外一种情况,如果在系统中增加一台服务器Memcached Server 04:
在这里插入图片描述
此时A、D、C不受影响,只有B需要重定位到新的Server04。
一般在一致性哈希算法中,如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即顺着逆时针方向行走遇到的第一台服务器)之间数据,其它不会受到影响。
总结:一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。
一致性哈希的缺点:在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。我们可以采用增加虚拟节点的方式解决。
更重要的是,集群中缓存服务器节点越多,增加/减少节点带来的影响越小。换句话说,随着集群规模的增大,继续命中原有缓存数据的概率会越来越大,虽然仍然有小部分数据缓存在服务器中不能被读到,但是这个比例足够小,即使访问数据库,也不会对数据库造成致命的负载压力。

二、MemCache实现原理

1.memcache的数据存放
首先要说明一点,MemCache的数据存放在内存中。

(1)访问数据的速度比传统的关系型数据库要快,因为Oracle、MySQL这些传统的关系型数据库为了保持数据的持久性,数据存放在硬盘中,IO操作速度慢。

(2)MemCache的数据存放在内存中,同时意味着只要MemCache重启,数据就会消失。

(3)既然MemCache的数据存放在内存中,那么势必受到机器位数的限制,32位机器最多只能使用2GB的内存空间,64位机器可以认为没有上限。

2.memcache的内存分配
MemCache最重要的是内存如何分配,MemCache采用的内存分配方式是固定空间分配,如下图所示:
在这里插入图片描述
这张图片里面涉及了slab_class、slab、page、chunk,它们之间的关系是:

(1)MemCache将内存空间分为一组slab;

(2)每个slab下又有若干个page,每个page默认是1M,如果一个slab占用100M内存,那么这个slab下应该有100个page;

(3)每个page里面包含一组chunk,chunk是真正存放数据的地方,同一个slab里面的chunk大小是固定的;

(4)有相同大小chunk的slab被组织在一起称为slab_class;

MemCache内存分配的方式称为allocator(分配运算),slab的数量是有限的,几个、十几个或者几十个,这个和启动参数的配置相关。
MemCache中的value存放的地方是由value的大小决定的,value总是会被存放到与chunk大小最接近的一个slab中,比如slab[1]的chunk大小为80字节、slab[2]的chunk大小为100字节、slab[3]的chunk大小为128字节(相邻slab内的chunk基本以1.25为比例进行增长,MemCache启动时可以用-f指定这个比例),那么过来一个88字节的value,这个value将被放到2号slab中。放入slab时,首先slab要申请内存,申请内存是以page为单位的,所以在放入第一个数据时,无论大小为多少,都会有1M大小的page被分配给该slab。
申请到page后,slab会将这个page的内存按chunk的大小进行切分,这样就变成了一个chunk数组,最后从这个chunk数组中选择一个用于存储数据。
如果这个slab中没有chunk可以分配了怎么办?如果MemCache启动没有追加-M(禁止LRU,这种情况下内存不够会报Out Of Memory错误),那么MemCache会把这个slab中最近最少使用的chunk中的数据清理掉,然后放上最新的数据。

三、Memcache的工作流程

在这里插入图片描述
1.memcache工作流程

(1)检查客户端的请求数据是否在memcached中,如果有,直接把请求数据返回,不再对数据库进行任何操作,路径操作为①②③⑦。

(2)如果请求的数据不在memcached中,就去查数据库,把从数据库中获取的数据返回给客户端,同时把数据缓存一份到memcached中(memcached客户端不负责,需要程序明确实现),路径操作为①②④⑤⑦⑥。

(3)每次更新数据库的同时更新memcached中的数据,保证一致性。

(4)当分配给memcached的内存空间用完后,会使用LRU(Least Recently Used,最近最少使用)策略加上到期失效策略,失效数据首先被替换,然后再替换掉最近未使用的数据。

2.Memcached特征

(1)协议简单
它是基于文本行的协议,直接通过telnet在memcached服务器上可进行存取数据操作。
注:文本行的协议:指的是信息以文本传送,一个信息单元传递完毕后要传送换行。
比如对于HTTP的GET请求来说,GET /index.html HTTP/1.1是一行,接下去每个头部信息各占一行。一个空行表示整个请求结束。

(2)基于libevent事件处理
Libevent是一套利用C开发的程序库,它将BSD系统的kqueue,Linux系统的epoll等事件处理功能封装成一个接口,与传统的select相比,提高了性能。

(3)内置的内存管理方式
所有数据都保存在内存中,存取数据比硬盘快,当内存满后,通过LRU算法自动删除不使用的缓存,但没有考虑数据的容灾问题,重启服务,所有数据会丢失。

(4)分布式
各个memcached服务器之间互不通信,各自独立存取数据,不共享任何信息。服务器并不具有分布式功能,分布式部署取决于memcache客户端。

(5)Memcache的安装分为两个过程:
memcache服务器端的安装和memcached客户端的安装。
服务器端的安装就是在服务器(一般都是linux系统)上安装Memcache实现数据的存储。
客户端的安装就是指php(或者其他程序,Memcache还有其他不错的api接口提供)去使用服务器端的Memcache提供的函数,需要php添加扩展。
四、nginx+php+memcache+mysql搭建

1.安装nginx
(在192.168.229.168主机操作)

[root@webapp ~]# cd /usr/local/src/
[root@webapp src]# ls
pcre-8.39.tar.gz  zlib-1.2.8.tar.gz
[root@webapp src]# wget http://nginx.org/download/nginx-1.18.0.tar.gz
[root@webapp src]# groupadd -r www
[root@webapp src]# useradd -r -g www -s /sbin/nologin -M www
[root@webapp src]# tar zxf pcre-8.39.tar.gz  #不需要编译,只需要解压;
[root@webapp src]# tar zxf zlib-1.2.8.tar.gz  #不需要编译,只需要解压;
[root@webapp src]# tar zxf nginx-1.18.0.tar.gz
[root@webapp src]# yum -y install gcc gcc-c++ make libtool openssl openssl-devel  #安装所需软件
[root@webapp src]# cd nginx-1.18.0 
[root@webapp nginx-1.18.0]# ./configure --prefix=/usr/local/nginx --with-http_dav_module --with-http_stub_status_module --with-http_addition_module --with-http_sub_module --with-http_flv_module --with-http_mp4_module --with-pcre=/usr/local/src/pcre-8.39 --with-zlib=/usr/local/src/zlib-1.2.8 --with-http_ssl_module --with-http_gzip_static_module --user=www --group=www
[root@webapp nginx-1.18.0]# make && make install
注意:
--with-pcre:用来设置pcre的源码目录;
--with-zlib:用来设置zlib的源码目录;
编译nginx需要用到这两个库的源码;
[root@webapp nginx-1.18.0]# ln -s /usr/local/nginx/sbin/nginx /usr/local/sbin/
[root@webapp nginx-1.18.0]# nginx -t
[root@webapp nginx-1.18.0]# nginx
[root@webapp nginx-1.18.0]# netstat -anput | grep nginx
tcp 0 0 0.0.0.0:80 0.0.0.0:* LISTEN 9834/nginx: master
[root@webapp nginx-1.18.0]# firewall-cmd --permanent --add-port=80/tcp
success
[root@webapp nginx-1.18.0]# firewall-cmd --reload
success

启动后可以再浏览器中打开页面,会显示nginx默认页面。
在这里插入图片描述
2、安装php(在nginx主机上安装)
所需软件包为:

libmcrypt-2.5.7.tar.gz
pcre-8.39.tar.gz
zlib-1.2.8.tar.gz
php-5.6.27.tar.gz

安装libmcrypt

[root@webapp ~]# cd /usr/local/src/
[root@webapp src]# ls
libmcrypt-2.5.7.tar.gz  pcre-8.39.tar.gz  php-5.6.27.tar.gz  zlib-1.2.8.tar.gz
[root@webapp src]# tar zxf libmcrypt-2.5.7.tar.gz
[root@webapp src]# cd libmcrypt-2.5.7
[root@webapp libmcrypt-2.5.7]# ./configure --prefix=/usr/local/libmcrypt && make && make install
[root@webapp libmcrypt-2.5.7]# yum -y install libxml2-devel libcurl-devel openssl-devel bzip2-devel
[root@webapp libmcrypt-2.5.7]# cd ..
[root@webapp src]# tar zxf php-5.6.27.tar.gz
[root@webapp src]# cd php-5.6.27
[root@webapp php-5.6.27]# ./configure --prefix=/usr/local/php5.6 --with-mysql=mysqlnd --with-pdo-mysql=mysqlnd --with-mysqli=mysqlnd --with-openssl --enable-fpm --enable-sockets --enable-sysvshm --enable-mbstring --with-freetype-dir --with-jpeg-dir --with-png-dir --with-zlib --with-libxml-dir=/usr --enable-xml --with-mhash --with-mcrypt=/usr/local/libmcrypt --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d --with-bz2 --enable-maintainer-zts
[root@webapp php-5.6.27]# make && make install
[root@webapp php-5.6.27]# cp php.ini-production /etc/php.ini
[root@webapp php-5.6.27]# vim /etc/php.ini
修改/etc/php.ini文件,将short_open_tag修改为on,修改后的内容如下:
short_open_tag = On  #支持php短标签;
[root@webapp php-5.6.27]# cp sapi/fpm/init.d.php-fpm /etc/init.d/php-fpm
[root@webapp php-5.6.27]# chmod +x /etc/init.d/php-fpm
[root@webapp php-5.6.27]# chkconfig --add php-fpm
[root@webapp php-5.6.27]# chkconfig php-fpm on
提供php-fpm配置文件并编辑:
[root@webapp php-5.6.27]# cp /usr/local/php5.6/etc/php-fpm.conf.default /usr/local/php5.6/etc/php-fpm.conf
[root@webapp php-5.6.27]# vim /usr/local/php5.6/etc/php-fpm.conf
修改内容如下:
pid = run/php-fpm.pid
listen =127.0.0.1:9000
pm.max_children = 300
pm.start_servers = 10
pm.min_spare_servers = 10
pm.max_spare_servers =50
启动php-fpm服务:
[root@webapp php-5.6.27]# service php-fpm start
Starting php-fpm done
[root@webapp php-5.6.27]# netstat -anput | grep php-fpm
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 10937/php-fpm: mast

3.安装mysql
(在192.168.229.161主机操作)
查看是否安装mariadb

[root@mysql ~]# rpm -qa | grep mariadb
[root@mysql ~]# rpm -e --nodeps mariadb-libs

首先创建目录用来存放软件包和编译安装脚本

[root@mysql ~]# mkdir -p /server/{soft,scripts}

把所需要的软件包移动到/server/soft目录下

cmake-2.8.6.tar.gz
mysql-5.6.36.tar.gz

编写编译安装脚本如下

[root@mysql ~]# vim /server/scripts/mysql.sh
#!/bin/bash
#由于没有下载mysql源码包,所以提前准备好
echo '正在下载资源包...'
yum -y install ncurses-devel gcc gcc-c++ 

tar zxf /server/soft/cmake-2.8.6.tar.gz -C /usr/src
cd /usr/src/cmake-2.8.6
echo '正在编译安装...'
./configure &> /dev/null
gmake && gmake install &> /dev/null

groupadd mysql
useradd -M -s /sbin/nologin mysql -g mysql

tar zxf /server/soft/mysql-5.6.36.tar.gz -C /usr/src
cd /usr/src/mysql-5.6.36
echo '预编译中...'
cmake -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DSYSCONFDIR=/etc -DDEFAULT_CHARSET=utf8 -DDEFAULT_COLLATION=utf8_general_ci -DWITH_EXTRA_CHARSETS=all &> /dev/null
echo  '正在编译安装...'
make && make install &> /dev/null

echo  '对数据库目录进行授权:'
chown -R mysql:mysql /usr/local/mysql
echo  '建立配置文件:'
rm -rf /etc/my.cnf
cp support-files/my-default.cnf /etc/my.cnf
echo '安装Perl模块...'
yum -y install perl-Data-Dumper &> /dev/null
echo '初始化数据库...'
/usr/local/mysql/scripts/mysql_install_db --user=mysql --basedir=/usr/local/mysql --datadir=/usr/local/mysql/data/
echo '设置环境变量:'
echo "PATH=$PATH:/usr/local/mysql/bin" >> /etc/profile
. /etc/profile
#mysql 的启动和关闭:
cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld
chmod +x /etc/init.d/mysqld
/etc/init.d/mysqld start

echo  '创建软连接,优化路径:'
ln -s /usr/local/mysql/bin/mysql /usr/local/bin
ln -s /usr/local/mysql/bin/mysqladmin /usr/local/bin
#/etc/init.d/mysqld是一个shell脚本,在启动过程中会调用mysqld_safe脚本,最后调用mysqld服务启动mysql,如下所示.
#$bindir/mysql_safe --datadir="$datadir" --pid-file="$mysqld_pid_file_path" $other_args >/dev/null 2>&1 
netstat -anpt | grep 3306
cat << EOF

****************************************
* Mysql  has been installed successfully. *
****************************************

EOF

4.安装memcached服务端
(在192.168.229.167主机操作)
memcached是基于libevent的事件处理。libevent是个程序库,它将Linux的epoll、BSD类操作系统的kqueue等事件处理功能封装成统一的接口。即使对服务器的连接数增加,也能发挥I/O的性能。memcached使用这个libevent库,因此能在Linux、BSD、Solaris等操作系统上发挥其高性能。
首先先安装memcached依赖库libevent

[root@mem ~]# cd /usr/local/src
[root@mem src]# ls
libevent-2.0.22-stable.tar.gz  memcached-1.6.6.tar.gz
[root@mem src]# tar zxf libevent-2.0.22-stable.tar.gz
[root@mem src]# cd libevent-2.0.22-stable/
[root@mem libevent-2.0.22-stable]# yum -y install gcc gcc-c++
[root@mem libevent-2.0.22-stable]# ./configure && make && make install
[root@mem libevent-2.0.22-stable]# cd ..
[root@mem src]# tar zxf memcached-1.6.6.tar.gz
[root@mem src]# cd memcached-1.6.6/
[root@mem memcached-1.6.6]# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/
[root@mem memcached-1.6.6]# make && make install
[root@mem memcached-1.6.6]# ln -s /usr/local/memcached/bin/* /usr/local/bin/

配置环境变量
进入用户宿主目录,编辑.bash_profile,为系统环境变量LD_LIBRARY_PATH增加新的目录,需要增加的内容如下:

[root@memcache memcached-1.6.6]# vim ~/.bash_profile
MEMCACHED_HOME=/usr/local/memcached
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MEMCACHED_HOME/lib

启动memcached服务

[root@mem memcached-1.6.6]# memcached -d -m 100 -l 192.168.229.167 -p 11211 -u root -c 10240 -P /usr/local/memcached/memcached.pid
[root@mem memcached-1.6.6]# firewall-cmd --permanent --add-port=11211/tcp
success
[root@mem memcached-1.6.6]# firewall-cmd --reload 
success
[root@mem memcached-1.6.6]# yum -y install telnet
[root@mem memcached-1.6.6]# telnet 192.168.229.167 11211
Trying 192.168.229.167...
Connected to 192.168.229.167.
Escape character is '^]'.

启动参数说明

-d:选项是启动一个守护进程;

-m:分配给Memcache使用的内存数量,单位是MB,默认64MB。

-l:监听的IP地址。(默认:INADDR_ANY,所有地址);

-p:设置Memcache的TCP监听端口,最好是1024以上的端口;

-u:运行Memcache的用户,如果当前为root,需要使用此参数指定用户;

-c:选项是最大运行的并发连接数,默认是1024。

-P:设置保存Memcache的pid文件;

-M:内存耗尽时返回错误,而不是删除项;

-f:块大小增长因子,默认是1.25;

-n:最小分配空间,key+value+flags默认是48;

-h:显示帮助;

刷新用户环境变量

[root@mem memcached-1.6.6]# source ~/.bash_profile

编写memcached服务启停脚本

[root@mem memcached-1.6.6]# vim /etc/init.d/memcached
脚本内容如下:
#!/bin/bash
#
#pidfile: /usr/local/memcached/memcached.pid
#memcached_home: /usr/local/memcached
#chkconfig: 35 21 79
#description: Start and stop memcached Service
#Source function library
. /etc/rc.d/init.d/functions
RETVAL=0
prog="memcached"
basedir=/usr/local/memcached
cmd=${basedir}/bin/memcached
pidfile="$basedir/${prog}.pid"
#interface to listen on (default: INADDR_ANY, all addresses)
ipaddr="192.168.229.167"
#listen port
port=11211
#username for memcached
username="root"
#max memory for memcached,default is 64M
max_memory=100
#max connections for memcached
max_simul_conn=10240
start() {
echo -n $"Starting service: $prog"  #-n不换行输出;
$cmd -d -m $max_memory -u $username -l $ipaddr -p $port -c $max_simul_conn -P $pidfile
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/$prog
}
stop() {
echo -n $"Stopping service: $prog "
run_user=$(whoami)
pidlist=$(ps -ef | grep $run_user | grep memcached | grep -v grep | awk '{print($2)}')
for pid in $pidlist
do
kill -9 $pid
if [ $? -ne 0 ]; then
return 1
fi
done
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/$prog
}
#See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
exit 1
esac
exit $RETVAL
[root@mem memcached-1.6.6]# chmod +x /etc/init.d/memcached 
[root@mem memcached-1.6.6]# chkconfig --add memcached
[root@mem memcached-1.6.6]#  chkconfig memcached on

说明
shell脚本中return的作用

(1)终止一个函数;

(2)return命令允许带一个整型参数,这个整数将作为函数的"退出状态码"返回给调用这个函数的脚本,并且这个整数也被赋值给变量$?;

(3)命令格式:return value;

5.配置nginx.conf文件
配置内容如下:

[root@webapp nginx-1.18.0]# cd /usr/local/nginx/conf
[root@webapp conf]# mv nginx.conf nginx.bak
[root@webapp conf]# vim nginx.conf
user www www;
worker_processes 2;
worker_cpu_affinity 01 10;
error_log logs/error.log;
#error_log logs/error.log notice;
#error_log logs/error.log info;
pid logs/nginx.pid;
    
    events {
        use epoll;
        worker_connections 65535;
        multi_accept on;
}
    
    http {
        include mime.types;
        default_type application/octet-stream;
        #log_format main '$remote_addr - $remote_user [$time_local] "$request" '
        #'$status $body_bytes_sent "$http_referer" '
        #'"$http_user_agent" "$http_x_forwarded_for"';
        #access_log logs/access.log main;
      sendfile on;
      tcp_nopush on;
      keepalive_timeout 65;
      tcp_nodelay on;
      client_header_buffer_size 4k;
      open_file_cache max=102400 inactive=20s;
      open_file_cache_valid 30s;
      open_file_cache_min_uses 1;
      client_header_timeout 15;
      client_body_timeout 15;
      reset_timedout_connection on;
      send_timeout 15;
      server_tokens off;
      client_max_body_size 10m;
      fastcgi_connect_timeout 600;
      fastcgi_send_timeout 600;
      fastcgi_read_timeout 600;
      fastcgi_buffer_size 64k;
      fastcgi_buffers 4 64k;
      fastcgi_busy_buffers_size 128k;
      fastcgi_temp_file_write_size 128k;
      fastcgi_temp_path /usr/local/nginx/nginx_tmp;
      fastcgi_intercept_errors on;
      fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:128m inactive=1d max_size=10g;
      
      gzip on;
      gzip_min_length 2k;
      gzip_buffers 4 32k;
      gzip_http_version 1.1;
      gzip_comp_level 6;
      gzip_types text/plain text/css text/javascript application/json application/javascript application/x-javascript application/xml;
      gzip_vary on;
      gzip_proxied any;
    
    server {
      listen 80;
      server_name www.benet.com;
      #charset koi8-r;
      #access_log logs/host.access.log main;
      
      location ~* ^.+\.(jpg|gif|png|swf|flv|wma|wmv|asf|mp3|mmf|zip|rar)$ {
      valid_referers none blocked www.benet.com benet.com;
      if ($invalid_referer) {
      #return 302 http://www.benet.com/img/nolink.jpg;
      return 404;
      break;
    }
      access_log off;
}
    location / {
      root html;
      index index.php index.html index.htm;
}
    location ~* \.(ico|jpe?g|gif|png|bmp|swf|flv)$ {
      expires 30d;
      #log_not_found off;
      access_log off;
}
    location ~* \.(js|css)$ {
      expires 7d;
      log_not_found off;
      access_log off;
} 
    location = /(favicon.ico|roboots.txt) {
      access_log off;
      log_not_found off;
}
    location /status {
      stub_status on;
}
    location ~ .*\.(php|php5)?$ {
      root html;
      fastcgi_pass 127.0.0.1:9000;
      fastcgi_index index.php;
      include fastcgi.conf;
      fastcgi_cache cache_fastcgi;
      fastcgi_cache_valid 200 302 1h;
      fastcgi_cache_valid 301 1d;
      fastcgi_cache_valid any 1m;
      fastcgi_cache_min_uses 1;
      fastcgi_cache_use_stale error timeout invalid_header http_500;
      fastcgi_cache_key http://$host$request_uri;
}
      #error_page 404 /404.html;
      #redirect server error pages to the static page /50x.html
      #
      error_page 500 502 503 504 /50x.html;
    location = /50x.html {
      root html;
    } 
  } 
}
[root@webapp conf]# nginx -s reload

编写一个php测试页

[root@webapp conf]# vim /usr/local/nginx/html/test.php
<?php
phpinfo ();
?>

使用浏览器访问192.168.229.168/test.php测试页
在这里插入图片描述
6.安装memcache客户端(在php服务器操作)
memcache分为服务端和客户端。服务端用来存放缓存,客户端用来操作缓存。
安装php扩展库(phpmemcache)。
安装PHP Memcache扩展:
可以使用php自带的pecl安装程序

[root@webapp ~]# /usr/local/servers/php/bin/pecl install memcache

也可以从源码安装,他是生成php的扩展库文件memcache.so。
安装memcache扩展库

[root@webapp src]# tar zxf memcache-3.0.8.tgz 
[root@webapp src]# cd memcache-3.0.8/
[root@webapp memcache-3.0.8]# /usr/local/php5.6/bin/phpize
[root@webapp memcache-3.0.8]# ./configure --enable-memcache --with-php-config=/usr/local/php5.6/bin/php-config
[root@webapp memcache-3.0.8]# make && make install
安装完后会有类似这样的提示:
Installing shared extensions: /usr/local/php5.6/lib/php/extensions/no-debug-zts-20131226/
把这个记住,然后修改php.ini
[root@webapp memcache-3.0.8]# vim /etc/php.ini
大概在45%适当位置添加一行
extension=/usr/local/php5.6/lib/php/extensions/no-debug-zts-20131226/memcache.so
[root@webapp memcache-3.0.8]# service php-fpm restart
Gracefully shutting down php-fpm .done
Starting php-fpm done

测试:
(1)检查php扩展是否正确安装

[root@webapp memcache-3.0.8]# /usr/local/php5.6/bin/php -m

命令行执行php -m查询结果中有memcache项,但是测试页却没有显示。原因是nginx配置文件中启用了fastcgi缓存,可以修改nginx.conf把关于fastcgi给注释掉即可。

[root@webapp memcache-3.0.8]# vim /usr/local/nginx/conf/nginx.conf
...
#fastcgi_cache_path /usr/local/nginx/fastcgi_cache levels=1:2 keys_zone=cache_fastcgi:128m inactive=1d max_size=10g;
...
#fastcgi_cache cache_fastcgi;
#fastcgi_cache_valid 200 302 1h;
#fastcgi_cache_valid 301 1d;
#fastcgi_cache_valid any 1m;
#fastcgi_cache_min_uses 1;
#fastcgi_cache_use_stale error timeout invalid_header http_500;
#fastcgi_cache_key http://$host$request_uri;
[root@webapp memcache-3.0.8]# nginx -s reload

浏览器访问192.168.229.168/test.php
在这里插入图片描述
测试代码

[root@webapp memcache-3.0.8]# vim /usr/local/nginx/html/test1.php 
<?php
$memcache = new Memcache;
$memcache->connect('192.168.229.167', 11211) or die ("Could not connect");
$version = $memcache->getVersion();
echo "Server's version: ".$version."<br/>";
$tmp_object = new stdClass;
$tmp_object->str_attr = 'test';
$tmp_object->int_attr = 123;
$memcache->set('key', $tmp_object, false, 10) or die ("Failed to save data at the server");
echo "Store data in the cache (data will expire in 10 seconds)<br/>";
$get_result = $memcache->get('key');
echo "Data from the cache:<br/>";
var_dump($get_result);
?>

浏览器访问192.168.229.168/test1.php
在这里插入图片描述
使用memcache服务器进行查看,只有10秒的生命周期。

 [root@mem memcached-1.6.6]# telnet 192.168.229.167 11211
Trying 192.168.229.167...
Connected to 192.168.229.167.
Escape character is '^]'.
get key
VALUE key 1 66
O:8:"stdClass":2:{s:8:"str_attr";s:4:"test";s:8:"int_attr";i:123;}
END
get key
END

使用memcache实现session共享
配置php.ini中的Session为memcache方式

[root@webapp memcache-3.0.8]# vim /etc/php.ini
session.save_handler = memcache
session.save_path = "tcp://192.168.229.167:11211?persistent=1&weight=1&timeout=1&retry_interval=15"

注意

session.save_handler:设置session的储存方式为memcache,默认以文件方式存取session数据。
如果想要使用自定义的处理来存取session数据,比如memcache方式则修为session.save_handler = memcache;

session.save_path:设置session储存的位置,多台memcache用逗号隔开,使用多个memcached server时用逗号”,”隔开,可以带额外的参数”persistent”、”weight”、” timeout”、”retry_interval”等;
类似这样的:"tcp://host:port?persistent=1&weight=2,tcp://host2:port2"。

memcache实现session共享也可以在某个一个应用中设置:
ini_set("session.save_handler", "memcache");
ini_set("session.save_path", "tcp://192.168.229.167:11211");
ini_set()只对当前php页面有效,并且不会去修改php.ini文件本身,也不会影响其他php页面。

测试memcache可用性
在web服务器上新建/usr/local/nginx/html/memcache.php 文件。

[root@webapp memcache-3.0.8]# vim /usr/local/nginx/html/memcache.php
<?php
session_start();
if (!isset($_SESSION['session_time']))
{
$_SESSION['session_time'] = time();
}
echo "session_time:".$_SESSION['session_time']."<br />";
echo "now_time:".time()."<br />"; 
echo "session_id:".session_id()."<br />";
?>

访问网址http://192.168.229.168/memcache.php可以查看session_time是否都是为memcache中的Session,同时可以在不同的服务器上修改不同的标识查看是否为不同的服务器上的。
在这里插入图片描述
可以直接用sessionid去memcached里查询一下:

[root@mem memcached-1.6.6]# telnet 192.168.229.167 11211
Trying 192.168.229.167...
Connected to 192.168.229.167.
Escape character is '^]'.
get hpcvmdh3n4v5aja1iikvjso013
VALUE hpcvmdh3n4v5aja1iikvjso013 0 26
session_time|i:1596447937;
END

得到 session_time|i:1479134997;这样的结果,说明session正常工作,默认memcache会监听11221端口,如果想清空服务器上memecache的缓存,一般使用的是:

[root@mem memcached-1.6.6]# telnet 192.168.229.167 11211
Trying 192.168.229.167...
Connected to 192.168.229.167.
Escape character is '^]'.
get hpcvmdh3n4v5aja1iikvjso013
VALUE hpcvmdh3n4v5aja1iikvjso013 0 26
session_time|i:1596449703;
END
flush_all
OK
get hpcvmdh3n4v5aja1iikvjso013
END

同样也可以使用:

[root@mem memcached-1.6.6]# echo "flush_all" | nc 192.168.229.167 11211
OK

使用flush_all后并不是删除\memcache上的key,而是置为过期memcache安全配置,因为memcache不进行权限控制,因此需要通过iptables将memcache仅开放各web服务器。
7.测试memcache缓存数据库数据
在 Mysql 服务器上创建测试表

mysql> create database testdb1;
Query OK, 1 row affected (0.00 sec)

mysql> use testdb1;
Database changed
mysql> create table test1(id int not null auto_increment,name varchar(20) default null,primary key (id)) engine=innodb auto_increment=1 default charset=utf8;
Query OK, 0 rows affected (0.03 sec)

mysql> insert into test1(name) values ('tom1'),('tom2'),('tom3'),('tom4'),('tom5');
Query OK, 5 rows affected (0.01 sec)
Records: 5 Duplicates: 0 Warnings: 0

mysql> select * from test1;
+----+------+
| id | name |
+----+------+
| 1 | tom1  |
| 2 | tom2  |
| 3 | tom3  |
| 4 | tom4  |
| 5 | tom5  |
+----+------+
5 rows in set (0.00 sec)

测试
下面就是测试的工作了,这里有个php脚本,用于测试memcache是否缓存数据成功。
需要为这个脚本添加一个只读的数据库用户,命令格式

mysql> grant select on testdb1.* to user@'%' identified by '123456';
Query OK, 0 rows affected, 1 warning (0.00 sec)

在web服务器上创建测试脚本内容如下:

[root@webapp memcache-3.0.8]# vim /usr/local/nginx/html/test_db.php
<?php
$memcachehost = '192.168.229.167';
$memcacheport = 11211;
$memcachelife = 60;
$memcache = new Memcache;
$memcache->connect($memcachehost,$memcacheport) or die ("Could not connect");
$query="select * from test1 limit 10";
$key=md5($query);
if(!$memcache->get($key))
{
$conn=mysql_connect("192.168.229.161","user","123456");
mysql_select_db(testdb1);
$result=mysql_query($query);
while ($row=mysql_fetch_assoc($result))
{
$arr[]=$row;
}
$f = 'mysql';
$memcache->add($key,serialize($arr),0,30);
$data = $arr ;
}
else{
$f = 'memcache';
$data_mem=$memcache->get($key);
$data = unserialize($data_mem);
}
echo $f;
echo "<br>";
echo "$key";
echo "<br>";
//print_r($data);
foreach($data as $a)
{
echo "number is <b><font color=#FF0000>$a[id]</font></b>";
echo "<br>";
echo "name is <b><font color=#FF0000>$a[name]</font></b>";
echo "<br>";
}
?>

访问192.168.229.168/test_db.php页面测试
在这里插入图片描述
刷新可看到
在这里插入图片描述

如果出现mysql表示memcached中没有内容,需要memcached从数据库中取得。再刷新页面,如果有memcache标志表示这次的数据是从memcached中取得的。memcached有个缓存时间默认是1分钟,过了一分钟后,memcached需要重新从数据库中取得数据。
查看Memcached缓存情况
使用telnet命令查看

[root@mem memcached-1.6.6]# telnet 192.168.229.167 11211
Trying 192.168.229.167...
Connected to 192.168.229.167.
Escape character is '^]'.
stats
STAT pid 1681  #Memcached进程的ID
STAT uptime 8429  #进程运行时间
STAT time 1479142306  #当前时间
STAT version 1.4.33  #Memcached版本
STAT libevent 2.0.22-stable
STAT pointer_size 64
STAT rusage_user 1.218430
STAT rusage_system 1.449512
STAT curr_connections 5
STAT total_connections 32
STAT connection_structures 10
STAT reserved_fds 20
STAT cmd_get 25  #总共获取数据的次数(等于get_hits+get_misses)
STAT cmd_set 19  #总共设置数据的次数
STAT cmd_flush 4
STAT cmd_touch 0
STAT get_hits 15  #命中了多少次数据,也就是从Memcached缓存中成功获取数据的次数
STAT get_misses 10  #没有命中的次数
STAT get_expired 3
STAT get_flushed 1
STAT delete_misses 0
STAT delete_hits 0
STAT incr_misses 2
STAT incr_hits 2
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT touch_hits 0
STAT touch_misses 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 3370
STAT bytes_written 15710
STAT limit_maxbytes 2147483648  #总的存储大小,默认为64M
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT time_in_listen_disabled_us 0
STAT threads 4
STAT conn_yields 0
STAT hash_power_level 16
STAT hash_bytes 524288
STAT hash_is_expanding 0
STAT malloc_fails 0
STAT log_worker_dropped 0
STAT log_worker_written 0
STAT log_watcher_skipped 0
STAT log_watcher_sent 0
STAT bytes 584  #当前所用存储大小
STAT curr_items 3
STAT total_items 17
STAT expired_unfetched 2
STAT evicted_unfetched 0
STAT evictions 0
STAT reclaimed 4
STAT crawler_reclaimed 0
STAT crawler_items_checked 0
STAT lrutail_reflocked 0
END
命中率= get_hits/ cmd_get
五、memcache相关指令

1.指令格式

<命令> <> <标记> <有效期> <数据长度>
<命令> - command name

主要是三个储存数据的三个命令

set命令:是保存一个叫做key的数据到服务器上;

add命令:是添加一个数据到服务器,但是服务器必须保证这个key是不存在的,能够保证数据不会被覆盖;

replace命令:是替换一个已经存在的数据,如果数据不存在,就是类似set功能;

说明

<> - key
就是保存在服务器上唯一的一个表示符,必须是跟其他的key不冲突,否则会覆盖掉原来的数据,这个key是为了能够准确的存取一个数据项目。

<标记> - flag
标记是一个16位的无符号整型数据,用来设置服务器端跟客户端一些交互的操作。

<有效期> - expiration time
是数据在服务器上的有效期限,如果是0,则数据永远有效,单位是秒,Memcache服务器端会把一个数据的有效期设置为当前Unix时间+设置的有效时间。

<数据长度> - bytes
数据的长度,block data块数据的长度,一般在这个个长度结束以后下一行跟着block data数据内容,发送完数据后,客户端一般等待服务器端的返回。

数据保存成功
STORED

数据保存失败,一般是因为服务器端这个数据key已经存在了。
NOT_STORED

2.数据提取命令
从服务器端提取数据主要是使用get指令。
格式:

get <>*

说明

<>* -key
key是一个不为空的字符串组合,发送这个指令以后,等待服务器的返回。

如果服务器端没有任何数据,则是返回:

END

证明不存在这个key,没有任何数据。
如果存在数据,则返回指定格式:

VALUE <> <标记> <数据长度> <数据块>

返回的数据是以VALUE开始的,后面跟着key和flags,以及数据长度,第二行跟着数据块。
返回内容说明

<> -key
是发送过来指令的key内容

<标记> - flags
是调用set指令保存数据时候的flags标记

<数据长度> - bytes
是保存数据时候定位的长度

<数据块> - data block
数据长度下一行就是提取的数据块内容

3.数据删除指令
数据删除指令也比较简单,使用delete指令。
格式:

delete <> <超时时间> <> - key

说明

key是你希望在服务器上删除数据的key键

<超时时间> - timeout
秒为单位,可选项,如果没有指定这个值,那么服务器上key数据将马上被删除,如果设置了这个值,那么数据将在超时时间后把数据清除,该项缺省值是0,表示永不过期。

删除数据后,服务器端会返回:

DELETED
删除数据成功

NOT_FOUND
这个key没有在服务器上找到。

如果要删除所有服务器上的数据,可以使用flush_all指令。
格式:

flush_all

这个指令执行后,服务器上所有缓存的数据都被删除,并且返回:

OK

这个指令一般不要使,除非你确实想把所有数据都干掉,删除完以后可是无法恢复的。
4.其他指令
如果想了解当前Memcache服务器的状态和版本等信息,可以使用状态查询指令和版本查询指令。
如果想了解当前所有Memcache服务器运行的状态信息,可以使用stats指令。
格式:

stats

服务器将返回每行按照STAT开始的状态信息,包括20项左右的信息,包括守护进程的pid、版本、保存的项目数量、内存占用、最大内存限制等信息。
如果只是想获取部分项目的信息,可以指定参数。
格式:

stats <参数>

这个指令将只返回指定参数的项目状态信息。
如果只是想单独了解当前版本信息,可以使用version指令。
格式:

version

将返回以VERSION开头的版本信息。
如果想结束当前连接,使用quit指令。
格式:

quit

5.Memcached连接
可以通过telnet命令并指定主机ip和端口来连接Memcached服务。
语法:

telnet HOST PORT 

命令中的HOST和PORT为运行Memcached服务的IP和端口。
实例
以下实例演示了如何连接到Memcached服务并执行简单的set和get命令。
本实例的Memcached服务运行的主机为127.0.0.1(本机)、端口为11211。

telnet 127.0.0.1 11211 
Trying 127.0.0.1... 
Connected to 127.0.0.1. 
Escape character is '^]'. 
set foo 0 0 3  #保存命令
bar  #数据
STORED  #结果
get foo  #取得命令
VALUE foo 0 3  #数据
bar  #数据
END  #结束行
quit  #退出

6.Memcached set命令
用于将value(数据值)存储在指定的key(键)中。
如果set的key已经存在,该命令可以更新该key所对应的原来的数据,也就是实现更新的作用。
set命令的基本语法格式如下:

set key flags exptime bytes [noreply] value 

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息。

exptime:在缓存中保存键值对的时间长度(以秒为单位,0表示永远)。

bytes:在缓存中存储的字节数。

noreply(可选):该参数告知服务器不需要返回数据。

value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)。

实例

key → runoob

flag → 0

exptime → 900(以秒为单位)

bytes → 9(数据存储的字节数)

value → memcached

set runoob 0 900 9
memcached 
STORED 
get runoob 
VALUE runoob 0 9
memcached 
END

输出
如果数据设置成功,则输出:

STORED

输出信息说明:

STORED:保存成功后输出。

ERROR:在保持失败后输出。

7.Memcached add命令
用于将value(数据值)存储在指定的key(键)中。
如果add的key已经存在,则不会更新数据(过期的key会更新),之前的值将仍然保持相同,并且将获得响应NOT_STORED。
add命令的基本语法格式如下:

add key flags exptime bytes [noreply] value

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息。

exptime:在缓存中保存键值对的时间长度(以秒为单位,0表示永远)。

bytes:在缓存中存储的字节数。

noreply(可选):该参数告知服务器不需要返回数据。

value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)。

实例

key → new_key

flag → 0

exptime → 900(以秒为单位)

bytes → 10(数据存储的字节数)

value → data_value

add new_key 0 900 10
data_value 
STORED 
get new_key 
VALUE new_key 0 10
data_value 
END

输出
如果数据添加成功,则输出:

STORED

输出信息说明:

STORED:保存成功后输出。

NOT_STORED:在保持失败后输出。

8.Memcached replace命令
用于替换已存在的key(键)的value(数据值)。
如果key不存在,则替换失败,并且您将获得响应NOT_STORED。
replace 命令的基本语法格式如下:

replace key flags exptime bytes [noreply] value

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息。

exptime:在缓存中保存键值对的时间长度(以秒为单位,0表示永远)。

bytes:在缓存中存储的字节数。

noreply(可选):该参数告知服务器不需要返回数据。

value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)。

实例

key → mykey

flag → 0

exptime → 900(以秒为单位)

bytes → 10(数据存储的字节数)

value → data_value

以下实例中使用的键位’mykey’并存储对应的值data_value。执行后替换相同的key的值为’some_other_value’。

add mykey 0 900 10
data_value 
STORED 
get mykey 
VALUE mykey 0 10
data_value 
END
replace mykey 0 900 16
some_other_value 
get mykey 
VALUE mykey 0 16
some_other_value 
END

输出
如果数据添加成功,则输出:

STORED

输出信息说明:

STORED:保存成功后输出。

NOT_STORED:执行替换失败后输出。

9.Memcached append命令
用于向已存在key(键)的value(数据值)后面追加数据 。
append命令的基本语法格式如下:

append key flags exptime bytes [noreply] value

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息。

exptime:在缓存中保存键值对的时间长度(以秒为单位,0表示永远)。

bytes:在缓存中存储的字节数。

noreply(可选): 该参数告知服务器不需要返回数据。

value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)。

实例
首先在Memcached中存储一个键runoob,其值为memcached。
然后使用get命令检索该值。
然后使用append命令在键为runoob的值后面追加"redis"。
最后再使用get命令检索该值。

set runoob 0 900 9
memcached 
STORED 
get runoob 
VALUE runoob 0 9
memcached 
END
append runoob 0 900 5
redis 
STORED 
get runoob 
VALUE runoob 0 14
memcachedredis 
END

输出
如果数据添加成功,则输出:

STORED

输出信息说明:

STORED:保存成功后输出。

NOT_STORED:该键在Memcached上不存在。

CLIENT_ERROR:执行错误。

10.Memcached prepend命令
用于向已存在key(键)的value(数据值)前面追加数据 。
prepend命令的基本语法格式如下:

prepend key flags exptime bytes [noreply] value 

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息。

exptime:在缓存中保存键值对的时间长度(以秒为单位,0表示永远)。

bytes:在缓存中存储的字节数。

noreply(可选):该参数告知服务器不需要返回数据。

value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)。

实例
首先在Memcached中存储一个键runoob,其值为memcached。
然后使用get命令检索该值。
然后使用prepend命令在键为runoob的值后面追加"redis"。
最后再使用get命令检索该值。

set runoob 0 900 9 
memcached 
STORED 
get runoob 
VALUE runoob 0 14 
memcached 
END 
prepend runoob 0 900 5 
redis 
STORED 
get runoob 
VALUE runoob 0 14 
redismemcached 
END 

输出
如果数据添加成功,则输出:

STORED 

输出信息说明:

STORED:保存成功后输出。

NOT_STORED:该键在Memcached上不存在。

CLIENT_ERROR:执行错误。

11.Memcached CAS命令
(Check-And-Set或Compare-And-Swap)用于执行一个"检查并设置"的操作。
它仅在当前客户端最后一次取值后,该key对应的值没有被其他客户端修改的情况下,才能够将值写入。
检查通过cas_token参数进行, 这个参数是Memcach指定给已经存在的元素的一个唯一的64位值。
CAS命令的基本语法格式如下:

cas key flags exptime bytes unique_cas_token [noreply] value 

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

flags:可以包括键值对的整型参数,客户机使用它存储关于键值对的额外信息。

exptime:在缓存中保存键值对的时间长度(以秒为单位,0表示永远)。

bytes:在缓存中存储的字节数。

unique_cas_token:通过gets命令获取的一个唯一的64位值。

noreply(可选):该参数告知服务器不需要返回数据。

value:存储的值(始终位于第二行)(可直接理解为key-value结构中的value)。

实例
要在Memcached上使用CAS命令,需要从Memcached服务商通过gets命令获取令牌(token)。
gets命令的功能类似于基本的get命令。两个命令之间的差异在于,gets返回的信息稍微多一些:64位的整型值非常像名称/值对的"版本"标识符。
实例步骤如下:
如果没有设置唯一令牌,则CAS命令执行错误。
如果键key不存在,执行失败。
添加键值对。
通过gets命令获取唯一令牌。
使用cas命令更新数据。
使用get命令查看数据是否更新。

cas tp 0 900 9 
ERROR <− 缺少token 
cas tp 0 900 9 2 
memcached 
NOT_FOUND <− 键tp不存在
set tp 0 900 9 
memcached 
STORED 
gets tp 
VALUE tp 0 9 1 
memcached 
END 
cas tp 0 900 5 1 
redis 
STORED 
get tp 
VALUE tp 0 5 
redis 
END 

输出
如果数据添加成功,则输出:

STORED 

输出信息说明:

STORED:保存成功后输出。

ERROR:保存出错或语法错误。

EXISTS:在最后一次取值后另外一个用户也在更新该数据。

NOT_FOUND:Memcached服务上不存在该键值。

12.Memcached get命令
获取存储在key(键)中的value(数据值),如果key不存在,则返回空。
get命令的基本语法格式如下:

get key

多个key使用空格隔开,如下:

get key1 key2 key3

参数说明如下:

key:键值 key-value结构中的key,用于查找缓存值。

在以下实例中,使用runoob作为key,过期时间设置为900秒。

set runoob 0 900 9
memcached 
STORED 
get runoob 
VALUE runoob 0 9
memcached 
END

13.Memcached gets命令
获取带有CAS令牌存的value(数据值),如果key不存在,则返回空。
gets命令的基本语法格式如下:

gets key 

多个key使用空格隔开,如下:

gets key1 key2 key3 

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

实例
在以下实例中,使用runoob作为key,过期时间设置为900秒。

set runoob 0 900 9 
memcached 
STORED 
gets runoob 
VALUE runoob 0 9 1 
memcached 
END 

在使用gets命令的输出结果中,在最后一列的数字1代表了key为runoob的CAS令牌。
14.Memcached delete命令
用于删除已存在的key(键)。
delete命令的基本语法格式如下:

delete key [noreply] 

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

noreply(可选):该参数告知服务器不需要返回数据。

实例
在以下实例中,使用runoob作为key,过期时间设置为900秒。之后使用delete命令删除该key。

set runoob 0 900 9 
memcached 
STORED 
get runoob 
VALUE runoob 0 9 
memcached 
END 
delete runoob 
DELETED 
get runoob 
END 
delete runoob 
NOT_FOUND 

输出
输出信息说明:

DELETED:删除成功。

ERROR:语法错误或删除失败。

NOT_FOUND:key不存在。

15.Memcached incr与decr命令
用于对已存在的key(键)的数字值进行自增或自减操作。
incr与decr命令操作的数据必须是十进制的32位无符号整数。
如果key不存在返回NOT_FOUND,如果键的值不为数字,则返回CLIENT_ERROR,其他错误返回ERROR。
incr命令的基本语法格式如下:

incr key increment_value 

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

increment_value:增加的数值。

实例
在以下实例中,使用visitors作为key,初始值为10,之后进行加5操作。

set visitors 0 900 2 
10 
STORED 
get visitors 
VALUE visitors 0 2 
10 
END 
incr visitors 5 
15 
get visitors 
VALUE visitors 0 2 
15 
END 

输出
输出信息说明:

NOT_FOUND:key不存在。

CLIENT_ERROR:自增值不是对象。

ERROR:其他错误,如语法错误等。

decr命令的基本语法格式如下:

decr key decrement_value 

参数说明如下:

key:键值key-value结构中的key,用于查找缓存值。

decrement_value:减少的数值。

实例
在以下实例中,使用visitors作为key,初始值为10,之后进行减5操作。

set visitors 0 900 2 
10 
STORED 
get visitors 
VALUE visitors 0 2 
10 
END 
decr visitors 5 
5 
get visitors 
VALUE 
visitors 0 1 
5 
END

输出
输出信息说明:

NOT_FOUND:key不存在。

CLIENT_ERROR:自增值不是对象。

ERROR:其他错误,如语法错误等。

16.Memcached stats命令
用于返回统计信息例如PID(进程号)、版本号、连接数等。
stats命令的基本语法格式如下:

stats

实例
在以下实例中,使用了stats命令来输出Memcached服务信息。

stats

这里显示了很多状态信息,状态项介绍:

pid:memcache服务器进程ID
uptime:服务器已运行秒数
time:服务器当前Unix时间戳
version:memcache版本
pointer_size:操作系统指针大小
rusage_user:进程累计用户时间
rusage_system:进程累计系统时间
curr_connections:当前连接数量
total_connections:Memcached运行以来连接总数
connection_structures:Memcached分配的连接结构数量
cmd_get:get命令请求次数
cmd_set:set命令请求次数
cmd_flush:flush命令请求次数
get_hits:get命令命中次数
get_misses:get命令未命中次数
delete_misses:delete命令未命中次数
delete_hits:delete命令命中次数
incr_misses:incr命令未命中次数
incr_hits:incr命令命中次数
decr_misses:decr命令未命中次数
decr_hits:decr命令命中次数
cas_misses:cas命令未命中次数
cas_hits:cas命令命中次数
cas_badval:使用擦拭次数
auth_cmds:认证命令处理的次数
auth_errors:认证失败数目
bytes_read:读取总字节数
bytes_written:发送总字节数
limit_maxbytes:分配的内存总大小(字节)
accepting_conns:服务器是否达到过最大连接(0/1)
listen_disabled_num:失效的监听数
threads:当前线程数
conn_yields:连接操作主动放弃数目
bytes:当前存储占用的字节数
curr_items:当前存储的数据总数
total_items:启动以来存储的数据总数
evictions:LRU 释放的对象数目
reclaimed:已过期的数据条目来存储新数据的数目

17.Memcached stats items命令
用于显示各个slab中item的数目和存储时长(最后一次访问距离现在的秒数)。
stats items命令的基本语法格式如下:

stats items

(1)stats slabs
用于显示各个slab的信息,包括chunk的大小、数目、使用情况等。
(2)stats sizes
用于显示所有item的大小和个数。
该信息返回两列,第一列是item的大小,第二列是item的个数。
实例

stats sizes STAT 96 1 END

18.Memcached flush_all命令
用于用于清理缓存中的所有key=>value(键=>值)对。
该命令提供了一个可选参数time,用于在制定的时间后执行清理缓存操作。
flush_all命令的基本语法格式如下:

flush_all [time] [noreply] 

实例
清理缓存:

set runoob 0 900 9 
memcached 
STORED 
get runoob 
VALUE runoob 0 9 
memcached 
END 
flush_all 
OK 
get runoob 
END
六、memcache分布式集群的搭建

Memcached是一个高性能的分布式内存对象缓存系统,用于动态Web应用以减轻数据库负载。它通过在内存中缓存数据和对象来减少读取数据库的次数,从而提高动态、数据库驱动网站的速度。Memcached基于一个存储键/值对的hashmap。其守护进程(daemon)是用C写的,但是客户端可以用任何语言来编写,并通过memcached协议与守护进程通信。
在这里插入图片描述
架构搭建流程
环境准备

192.168.229.170 magent1
192.168.229.174 magent2
192.168.229.152 memcache1
192.168.229.175 memcache2
关闭防火墙和selinux

1.安装libevent软件(4台相同操作)

[root@magent1 ~]# cd /usr/local/src/
[root@magent1 src]# ls
libevent-2.0.22-stable.tar.gz  magent-0.6.tar.gz
[root@magent1 src]# tar zxf libevent-2.0.22-stable.tar.gz
[root@magent1 src]# cd libevent-2.0.22-stable/
[root@magent1 libevent-2.0.22-stable]# yum -y install gcc gcc-c++
[root@magent1 libevent-2.0.22-stable]# ./configure
[root@magent1 libevent-2.0.22-stable]# make && make install

2.安装memcached软件(Memcached服务器2台)

[root@memcache1 ~]# cd /usr/local/src/
[root@memcache1 src]# tar zxf memcached-1.6.6.tar.gz
[root@memcache1 src]# cd memcached-1.6.6/
[root@memcache1 memcached-1.6.6]# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local
[root@memcache1 memcached-1.6.6]# make && make install
[root@memcache1 memcached-1.6.6]# ln -s /usr/local/memcached/bin/* /usr/local/bin/

主缓存

[root@memcache1 memcached-1.6.6]# memcached -d -m 100 -l 192.168.229.152 -p 11211 -u root -c 10240 -P /usr/local/memcached/memcached.pid
[root@memcache1 memcached-1.6.6]# netstat -anput | grep memcached

备缓存

[root@memcache2 memcached-1.6.6]# memcached -d -m 100 -l 192.168.229.175 -p 11211 -u root -c 10240 -P /usr/local/memcached/memcached.pid
[root@memcache2 memcached-1.6.6]# netstat -anput | grep memcached

3.安装magent软件(Magent服务器2台)

[root@magent1 ~]# cd /usr/local/src/
[root@magent1 src]# mkdir -p /usr/magent
[root@magent1 src]# tar zxf magent-0.6.tar.gz -C /usr/magent/
[root@magent1 src]# cd /usr/magent/
[root@magent1 magent]# vim ketama.h
开头添加:
#ifndef SSIZE_MAX
#define SSIZE_MAX 32767
#endif
[root@magent1 magent]# ln -s /usr/lib64/libm.so /usr/lib64/libm.a
[root@magent1 magent]# ln -s /usr/local/lib/libevent-2.0.so.5 /usr/lib64/libevent.a
[root@magent1 magent]# ldconfig
[root@magent1 magent]# make
[root@magent1 magent]# cp magent /usr/bin/
[root@magent1 magent]# vim /etc/ld.so.conf
添加:
/usr/local/lib
[root@magent1 magent]# ldconfig
[root@magent1 magent]# magent --help

主缓存和备缓存一样的启动命令(-l是漂移IP还没有搭建Keepalived服务,暂时不要启动Magent服务)
4.安装keepalived软件(Magent服务器2台)

[root@magent1 magent]# cd /usr/local/src/
[root@magent1 src]# yum -y install kernel-devel popt-devel openssl-devel
[root@magent1 src]# wget https://www.keepalived.org/software/keepalived-2.1.5.tar.gz
[root@magent1 src]# tar -zxf keepalived-2.1.5.tar.gz
[root@magent1 src]# cd keepalived-2.1.5/
[root@magent1 src]# ./configure --prefix=/
[root@magent1 src]# make && make install

配置主缓存服务器

[root@magent1 keepalived-2.1.5]# vim /etc/keepalived/keepalived.conf
修改:
global_defs {
    router_id LVS_1
}
vrrp_instance VI_1 {
    state MASTER
    interface ens33
    virtual_router_id 51
    priority 100
    advert_int 1
    authentication {
            auth_type PASS
            auth_pass 1111
    }
    virtual_ipaddress {
            192.168.229.100
    }
}
[root@magent1 keepalived-2.1.5]# systemctl start  keepalived
[root@magent1 keepalived-2.1.5]# ip add show dev ens33

配置备缓存服务器

[root@magent2 keepalived-2.1.5]# vim /etc/keepalived/keepalived.conf
修改:
global_defs {
    router_id LVS_2
}
vrrp_instance VI_1 {
    state BACKUP
    priority 50
    ......
virtual_ipaddress {
    192.168.229.100
  }
}
其他参数与主缓存服务器保持一致
[root@magent2 keepalived-2.1.5]# systemctl start  keepalived
[root@magent2 keepalived-2.1.5]# ip add show dev ens33

启动magent

[root@magent1 magent]# magent -u root -n 10240 -l 192.168.229.100 -p 12000 -s 192.168.229.152:11211 -b 192.168.229.175:11211
[root@magent1 magent]# ps -elf | grep magent
magent1关闭keepalived
[root@magent1 magent]# vim /lib/systemd/system/keepalived.service
注释掉这行
#KillMode=process
[root@magent1 system]# systemctl daemon-reload
[root@magent1 magent]# systemctl stop keepalived
实在关不了可以使用
[root@magent1 magent]# systemctl kill keepalived
magent2启动magent服务
[root@magent2 magent]# magent -u root -n 10240 -l 192.168.229.100 -p 12000 -s 192.168.229.152:11211 -b 192.168.229.175:11211
magent1开启keepalived
[root@magent1 magent]# systemctl start keepalived
[root@localhost ~]# ps -elf | grep magent

参数解释

-u:用户

-n:最大连接数

-l:magent对外监听IP地址

-p:magent对外监听端口

-s:magent主缓存IP地址和端口

-b:magent备缓存IP地址和端口

5.验证

[root@magent1 magent]# yum -y install telnet

(1)用主缓存节点连接上主缓存的12000端口插入数据

[root@magent1 magent]# telnet 192.168.229.100 12000
Trying 192.168.229.100...
Connected to 192.168.229.100.
Escape character is '^]'.
set key 0 0 1
a
STORED
quit
Connection closed by foreign host.

(2)查看插入的数据

[root@magent1 magent]# telnet 192.168.229.100 12000
Trying 192.168.229.100...
Connected to 192.168.229.100.
Escape character is '^]'.
get key
VALUE key 0 1
a
END
quit
Connection closed by foreign host.

(3)连接主缓存节点的11211端口进行查看

[root@magent1 magent]# telnet 192.168.229.152 11211
Trying 192.168.229.152...
Connected to 192.168.229.152.
Escape character is '^]'.
get key
VALUE key 0 1
a
END
quit
Connection closed by foreign host.

(4)连接备缓存节点的11211端口进行查看

[root@magent1 magent]# telnet 192.168.229.175 11211
Trying 192.168.229.175...
Connected to 192.168.229.175.
Escape character is '^]'.
get key
VALUE key 0 1
a
END
quit
Connection closed by foreign host.

说明主缓存节点和备缓存节点都有数据。
宕掉主缓存节点
停止memcached进程(或者断开主缓存节点的网卡)客户端查看

[root@magent1 magent]# telnet 192.168.229.100 12000
Trying 192.168.229.100...
Connected to 192.168.229.100.
Escape character is '^]'.
get key
VALUE key 0 1
a
END

总结

memcache的优点:可以做多主或者多从;

memcache的缺点:当主缓存节点当掉又恢复,之前的缓存数据会丢失;
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值