目录
案例前置知识点
Memcached
概念
- 是一套开源的高性能分布式内存对象缓存系统
- 所有数据都存储在内存中
- 支持任意存储类型的数据
- 非关系型数据库
- 提高网站的访问速度
部署场景
Memcached是典型的 C/S 架构,因此需要构建服务端与Memcached API客户端。
如果要使用Memcached,是需要开发人员编写API接口程序,由API接口去连接另一端,运维人员只负责平台的搭建
Memcached常用架构
流程
- 当客户端访问Web服务器时,Web服务器会通过Memcached API程序去连接Memcached服务器
- 如果Memcached的数据库里有用户要请求的数据,就直接返回给用户
- 如果数据库中没有要请求的数据,就请求MySQL查询数据
- 在MySQL找到数据了就返回给Memcached,然后再返回给客户端
Memcached
Memcached经常用于为数据存储做前端缓存
对于关系型数据库(MySQL),并发I/O的数据量很大时,数据库会承载很高的压力,因为关系型数据库是基于磁盘存储数据,可能会导致客户端的数据延迟较大
但是在Web服务器和MySQL数据库中间加一个缓存服务器,那也就意味着Web服务器获取数据不是直接从MySQL获取,而是从缓存服务器获取
Memcached API
Memcached API程序通常安装在客户端,在上图的环境中,Web服务器就是Memcached的客户端,再由开发人员在网页的代码里添加连接到Memcached服务端的语句
Memcached API是前端应用程序和缓存之间一个桥梁
数据存储方式
- 数据存储方式:Slab Allocation
按组分配存储空间,每次先分配一个Slab,一个Slab的大小为1M,然后在1M的空间里根据数据划分大小相同的Chunk。
Chunk的大小是根据数据总量进行均分,均分后的每一个Chunk大小是相同的
数据过期方式
像Memcached这种基于内存的非关系型数据库,存储的数据不会一直存储下去,为了解决这种问题就有了过期方式
当数据过期以后,就会清理掉
-
LRU
- 数据空间不足时,会根据LRU的情况淘汰最近使用最少的记录
-
Lazy Expiration
- 惰性过期,指的是使用get时查看记录时间,从而检查记录是否已经过期
Memcached缓存机制
当程序写入缓存数据时,Memcached的API接口将Key输入路由算法模块路由到集群中一台服务,之后由API接口与服务器进行通信,完成一次分布式缓存写入
Memcached路由算法
求余数hash算法
- 先用Key做hash运算得到一串16进制的数字,再做hash算法,根据余数进行路由
- 适合大多数数据需求,但是不适合用在动态变化的环境中
- 消耗性能少,速度更快
一致性hash算法
- 一致性哈希算法的核心思想是将所有节点和数据项映射到一个环形的哈希空间上,从而实现数据的均匀分布。
- 当节点发生变动时,只需要对部分数据进行重新分配,这大大降低了数据迁移的成本。通过这种方式,一致性哈希算法在分布式系统中实现了高效的数据管理和负载均衡。
- 适合在动态变化的环境中使用
- 生成时消耗性能较多,解密时速度慢
Memcached分布式
- 依赖于Memcached的客户端来实现
- 多个Memcached服务器是独立的
- 分布式数据如果存储是由路由算法决定的
利用路由算法结合Key,为Key生成一个hash整数值,通过这个整数来匹配对应的哪个Memcached服务器,最后把这个数据写入到该服务器
路由:这里的路由不是路由器概念上的路由,而是通过对应算法来决定把数据写入到哪个Memcached服务器,尽量做到平均
案例
注意:
如果要做高可用的集群环境,就需要使用专门针对高可用集群的Memcached软件包
如果要做单节点的部署,用的软件包和集群环境的Memcached软件包是不一样的
也就是说如果想把单节点的Memcached服务器更改为高可用集群环境,需要重新安装Memcached
单节点Memcached缓存系统案例
案例环境
操作系统 | IP 地址 | 角色 |
Centos 7 | 192.168.10.101 | Memcached服务器 |
Centos 7 | 192.168.10.103 | Memcached API和LAMP客户端 |
初步设置
打开101和103两台CentOS 7虚拟机,并连接上XShell
修改主机名
为了区分两台主机,使用hostnamectl命令设置主机名为对应的角色
在101主机设置
[root@localhost ~]# hostnamectl set-hostname memcache1
[root@localhost ~]# bash
在103主机设置
[root@localhost ~]# hostnamectl set-hostname memcached-api
[root@localhost ~]# bash
安装Memcached
在101主机(服务端)操作
为了方便实验关闭防火墙和内核安全机制
[root@memcache1 ~]# systemctl stop firewalld
[root@memcache1 ~]# setenforce 0
Memcached需要事件通知库来作为基本的运行环境,先导入该软件包到系统中
安装依赖,解压源码包,进入解压目录,指定安装参数,安装
[root@memcache1 ~]# yum -y install gcc*
[root@memcache1 ~]# tar zxvf libevent-2.1.8-stable.tar.gz
[root@memcache1 ~]# cd libevent-2.1.8-stable
[root@memcache1 libevent-2.1.8-stable]# ./configure --prefix=/usr/local/libevent
[root@memcache1 libevent-2.1.8-stable]# make && make install
再导入Memcached针对单节点的服务端源码包到系统
回到root家目录,解压源码包,进入解压目录,指定安装参数,安装
- --with-libevent:指定libevent函数库的位置
[root@memcache1 libevent-2.1.8-stable]# cd
[root@memcache1 ~]# tar zxvf memcached-1.5.1.tar.gz
[root@memcache1 ~]# cd memcached-1.5.1
[root@memcache1 memcached-1.5.1]# ./configure --prefix=/usr/local/memcached --with-libevent=/usr/local/libevent/
[root@memcache1 memcached-1.5.1]# make && make install
回到root家目录,编写一个能够方便管理Memcached状态的脚本,因为脚本中用到了killall命令,所以需要安装killall命令的依赖软件包
[root@memcache1 memcached-1.5.1]# cd
[root@memcache1 ~]# vim memcached_service.sh
[root@memcache1 ~]# yum -y install psmisc
脚本内容如下
#!/bin/bash
CMD="/usr/local/memcached/bin/memcached"
start(){
$CMD -d -m 128 -u root
}
stop(){
killall memcached;
}
ACTION=$1
case $ACTION in
'start')
start;;
'stop')
stop;;
'restart')
stop
sleep 2
start;;
*)
echo 'Usage:{start|stop|restart}'
esac
然后为该脚本添加执行权
[root@memcache1 ~]# chmod +x memcached_service.sh
然后使用该脚本启动Memcached,再使用netstat命令查看该脚本是否在运行
[root@memcache1 ~]# ./memcached_service.sh start
[root@memcache1 ~]# netstat -anpt | grep memcached
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 10099/memcached
tcp6 0 0 :::11211 :::* LISTEN 10099/memcached
配置客户端
部署LAMP
在103主机(客户端)操作
先用本地光盘安装gcc相关的软件包
[root@memcached-api ~]# yum -y install gcc*
我们要安装LAMP的环境,而有些软件包本地光盘是没有的,我们这里把仓库源替换成阿里云的yum仓库源
直接复制下方命令到终端回车
rm -rf /etc/yum.repos.d/*
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
curl -o /etc/yum.repos.d/epel.repo https://mirrors.aliyun.com/repo/epel-7.repo
yum clean all
为了快速部署,使用yum安装LAMP的环境
[root@memcached-api ~]# yum -y install httpd mariadb mariadb-server php php-devel php-mysql
开启LAMP的相关服务,设置MySQL密码,关闭防火墙和内核安全机制
[root@memcached-api ~]# systemctl start mariadb
[root@memcached-api ~]# mysqladmin -uroot password 'pwd123'
[root@memcached-api ~]# systemctl start httpd
[root@memcached-api ~]# systemctl stop firewalld
[root@memcached-api ~]# setenforce 0
在Apache存放网页文件的目录下创建一个用来测试的页面。内容如下
[root@memcached-api ~]# vim /var/www/html/test1.php
<?php
phpinfo();
?>
使用宿主机的浏览器访问:192.168.10.103/test1.php测试能否显示php版本信息页
安装Memcached API
先安装Memcached API所需的函数库,导入所需的函数库,这个函数库是Memcached提供的
解压软件包,进入解压目录,指定安装参数,安装
- --with-memcached:指定Memcached API的安装路径,虽然还没有安装Memcached,但在这里需要先指定出来
[root@memcached-api ~]# tar zxvf libmemcached-1.0.18.tar.gz
[root@memcached-api ~]# cd libmemcached-1.0.18
[root@memcached-api libmemcached-1.0.18]# ./configure --prefix=/usr/local/libmemcached --with-memcached=/usr/local/memcached
[root@memcached-api libmemcached-1.0.18]# make && make install
在这个LAMP的环境中,是PHP要去连接Memcached服务器,但是现在PHP并没有连接Memcached服务器的功能
在浏览器的测试页面中按下Ctrl + F搜索memcache,可以发现PHP是提供了这个模块的,但是现在我们还没有开启
导入Memcached API 程序的源码包到系统,利用该程序把Memcached功能扩展给PHP
安装zlib压缩工具,解压软件包,进入解压目录,生成Configure脚本,安装
- --with-php-config:指定php配置脚本的位置
- -with-libmemcached-dir:指定刚才安装的Memcached函数库位置
- --disable-memcached-sasl:禁用sasl认证机制功能
- --with-zlib-dir:指定zlib压缩工具的路径,如果使用yum安装(yum -y install zlib zlib-devel)的话,就不需要指定,如果是源码包安装的,就需要知道安装的位置
[root@memcached-api ~]# yum -y install zlib zlib-devel
[root@memcached-api ~]# tar zxvf memcached-2.2.0.tgz
[root@memcached-api ~]# cd memcached-2.2.0
[root@memcached-api memcached-2.2.0]# phpize
[root@memcached-api memcached-2.2.0]# ./configure --with-php-config=/usr/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached/ --disable-memcached-sasl --with-zlib-dir
[root@memcached-api memcached-2.2.0]# make && make install
让PHP应用指定的模块,需要打开PHP配置文件,在第2行([PHP]单元内)指定模块的.so文件
[root@memcached-api ~]# vim /etc/php.ini
extension=memcached.so # 第2行
然后重启Apache服务
[root@memcached-api ~]# systemctl restart httpd
然后使用宿主机的浏览器刷新网页,可以看到页面中有单独单元的memcached模块已经被支持了(memcached support)
此时PHP就可以通过Memcached API连接Memcached服务器了
但是连接Memcached服务器还需要配置连接参数,cd进入Apache存放网站文件的目录下,创建一个测试连接Memcached服务器的php文件,添加以下内容,注意addServer的IP地址要指定为Memcached服务器的IP地址
在参数中,我们指定了在Memcached中创建键值对,其中键是Key,值为 "Memcache test successful!",0表示过期时间,60表示字节数,代表要添加的数据是60个字节
[root@memcached-api ~]# cd /var/www/html/
[root@memcached-api html]# vim test.php
<?php
$memcache = new Memcached();
$memcache->addServer('192.168.10.101', 11211);
$memcache->set('key', 'Memcache test successful!', 0, 60);
$result = $memcache->get('key');
unset($memcache);
echo $result;
?>
然后再使用宿主机的浏览器访问Web服务器的IP + 该网页的文件名(192.168.10.103/test.php)
如果能够成功显示这一段字符串,也说明这一段字符串被存储到Memcached内了($memcache->set)
连接到Memcached查看数据
在101主机(Memcached服务端)操作
安装telnet工具来连接Memcached
[root@memcache1 ~]# yum -y install telnet
使用netstat命令可以看到Memcached的监听端口号是11211
[root@memcache1 ~]# netstat -anpt | grep memcached
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 10099/memcached
tcp6 0 0 :::11211 :::* LISTEN 10099/memcached
那么我们使用telnet命令指定本地地址 + Memcached端口号就可以连接进Memcached内
如果要退出连接,可以使用quit命令
[root@memcache1 ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
使用get 键名指定键来获取对应值,就可以看到我们刚才存储到Memcached的键值对了
get key
VALUE key 3932160 25
Memcache test successful!
END
Memcached的常用命令
添加(add)命令
使用add命令创建键值对
- 0 0 3:标记位为0、过期时间为0(不过期)、值占用的字节数
- 如果出现打错字的情况,使用Ctrl + 退格键删除输入
[root@memcache1 ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
add username 0 0 3 # 输入
tom # 输入
STORED
get username # 输入
VALUE username 0 3
tom
END
但是如果指定的字节数和值的字节数不对等,就会出现报错
add name 0 0 8
john
john
CLIENT_ERROR bad data chunk
ERROR
gets命令
gets命令用于查看该键值对的更多信息,比get命令输出的信息更多
使用gets命令来查询键值对数据,可以看到输出了3个数字 ——》0 3 2
- 0:过期时间
- 3:字节长度
- 2:更新因子,表示当前这个键(username)更新的次数(比如修改值、追加)
- 如果想修改一个键对应的值,需要指定对应的更新因子
gets username
VALUE username 0 3 2
tom
END
cas命令(更新)
使用cas命令指定键名,再指定标记位、过期时间、新字节长度、更新因子,就可以修改该键对应的值,但是注意新值的字节长度可以改为指定的字节长度
cas更新完值,最后使用gets命令查看username键,可以看到更新因子变成4了
cas username 0 0 5 2
12345
STORED
get username
VALUE username 0 5
12345
END
gets username
VALUE username 0 5 3
12345
END
追加(append)命令
append命令用于给一个键的值末尾追加数据
使用append命令指定键名,然后指定必要信息,其中的4表示要追加的字节数
使用gets命令查看键值对,可以看到字节数变成了7,更新因子变成了4
append username 0 0 4
0000
STORED
gets username
VALUE username 0 9 4
123450000
END
清除所有缓存数据(flush_all)
flush_all命令可以清除所有缓存数据,再使用get命令已经查询不到username这个键了
flush_all
OK
get username
END
如果要退出连接,可以使用quit命令
Memcached主主复制和高可用案例
本案例的目的是为了实现:
当Memcached服务器故障时,有从服务器能够继续维持服务正常,并且从服务器的数据和主服务器的数据是同步的
Web服务器在通过Memcached API连接服务器时,会使用VIP连接而不是单独的IP
案例环境
恢复101主机的快照,开启102主机,103主机在这个案例中继续使用
操作系统 | IP 地址 | 角色 |
Centos7 | 192.168.10.101 | Memcache服务端① |
Centos7 | 192.168.10.102 | Memcache服务端② |
Centos7 | 192.168.10.103 | Memcached API和LAMP |
初步设置
启动2台主机并连接上XShell(先启动101和102)
修改主机名
为了区分两台服务端主机,使用hostnamectl命令设置主机名为对应的角色
在101主机设置
[root@localhost ~]# hostnamectl set-hostname memcache1
[root@localhost ~]# bash
在102主机设置
[root@localhost ~]# hostnamectl set-hostname memcache2
[root@localhost ~]# bash
部署Memcached服务端
由于两个主机的操作是一样的,开启会话同步
在101(Memcached服务器①)操作
为了方便实验,关闭防火墙和内核安全机制,安装gcc相关软件包
[root@memcache1 ~]# systemctl stop firewalld
[root@memcache1 ~]# setenforce 0
[root@memcache1 ~]# yum -y install gcc*
Memcached需要事件通知库来作为基本的运行环境,先导入该软件包到两个主机中
解压源码包,进入解压目录,指定安装参数,安装
[root@memcache1 ~]# tar zxvf libevent-2.1.8-stable.tar.gz
[root@memcache1 ~]# cd libevent-2.1.8-stable
[root@memcache1 libevent-2.1.8-stable]# ./configure --prefix=/usr/local/libevent
[root@memcache1 libevent-2.1.8-stable]# make && make install
现在我们要部署高可用的Memcached环境,Memcached提供给单节点和高可用的软件包是不一样的
这里我们导入Memcached带有复制功能的软件包到两个主机中
解压源码包,进入解压目录,配置安装参数
- --enable-replication:启用复制功能
[root@memcache1 ~]# tar zxvf memcached-1.2.8-repcached-2.2.tar.gz
[root@memcache1 ~]# cd memcached-1.2.8-repcached-2.2
[root@memcache1 memcached-1.2.8-repcached-2.2]# ./configure --prefix=/usr/local/memcached_replication --enable-replication --with-libevent=/usr/local/libevent/
因为是CentOS系统,并不是FreeBSD和APPLE的系统,所以需要修改源代码,把图中两行删掉,在第57行和第59行
[root@memcache1 memcached-1.2.8-repcached-2.2]# vim memcached.c
然后安装
[root@memcache1 memcached-1.2.8-repcached-2.2]# make && make install
把libevent函数库文件提供给Memcached
[root@memcache1 ~]# ln -s /usr/local/libevent/lib/libevent-2.1.so.6 /usr/lib64/
配置Memcached服务端
关闭会话同步
后续操作就不一致了,所以关闭会话同步
在101(Memcached服务器①)操作
先启动Memcached程序,指定一些启动选项,启动时连接到对端服务器,然后使用netstat命令查看是否能够监听到102
- -d:以守护进程的方式启动
- -u:运行该程序时的用户
- -m:启动时为Memcached分配内存的大小,单位兆(Mb),如果不指定内存大小,默认是64兆
- -x:指定对端服务器的IP
[root@memcache1 ~]# /usr/local/memcached_replication/bin/memcached -d -u root -m 128 -x 192.168.10.102
[root@memcache1 ~]# netstat -anpt | grep memcached
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 20243/memcached
tcp 0 0 192.168.10.101:36580 192.168.10.102:11212 ESTABLISHED 20243/memcached
tcp6 0 0 :::11211 :::* LISTEN 20243/memcached
在102(Memcached服务器②)操作
在另一个服务端做相同操作,但是连接的IP不一样,启动后也是要netstat命令查看是否监听到101
[root@memcache2 ~]# /usr/local/memcached_replication/bin/memcached -d -u root -m 128 -x 192.168.10.101
[root@memcache2 ~]# netstat -anpt | grep memcached
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 10167/memcached
tcp 0 0 192.168.10.102:55500 192.168.10.101:11212 ESTABLISHED 10167/memcached
tcp6 0 0 :::11211 :::* LISTEN 10167/memcached
如果使用netstat命令查看时没有监听对端IP的条目,可以使用pkill memcached先杀死该服务的进程,然后再尝试执行/usr/local/memcached_replication/bin/memcached文件启动
测试
在101(Memcached服务器①)操作
给101安装一个tenet来测试两个Memcached服务器的数据是否同步
连接进本机的Memcached
[root@memcache1 ~]# yum -y install telnet
[root@memcache1 ~]# telnet 192.168.10.101 11211
创建一个键值对,然后确保get能够查询到,退出
set username 0 0 3
tom
STORED
get username
VALUE username 0 3
tom
END
quit
Connection closed by foreign host.
退出后,再连接102的Memcached
[root@memcache1 ~]# telnet 192.168.10.102 11211
get查询键值对,能够查到,就说明两台Memcached服务器数据同步复制了
get username
VALUE username 0 3
tom
END
quit
Connection closed by foreign host.
部署Keepalived实现故障转移
为了确保故障转移的高可用,我们需要一个VIP,通过Keepalived就可以让客户端连接VIP,当其中一台服务器故障了VIP就自动飘到另一个服务器上
开启会话同步
在101(Memcached服务器①)操作
再开启会话同步,给两个主机安装Keepalived,然后打开配置文件
[root@memcache1 ~]# yum -y install keepalived
[root@memcache1 ~]# vim /etc/keepalived/keepalived.conf
关闭会话同步
由于两台主机的配置文件有部分参数不能一致,所以关闭会话同步
在101(Memcached服务器①)操作
先在101的配置文件中修改下列参数,然后把第34行以下的参数全部删除(输入位置移到第34行,按小写d大写G)
- Master不会触发不抢占的参数,所以要把Master改成BACKUP,因为我们设置了101的优先级比102高,所以VIP还是优先分配给101
但是现在VRRP只会检测设备的状态,而不是针对服务的状态,比如某个服务已经故障了,但是这个主机没有故障,那么VRRP就会认为该节点没有故障
这里我们编写一个检查服务状态的脚本,只要该服务还在运行就不作操作,如果不运行就关闭Keepalived服务,让从节点认为该设备已经故障,由此来进行主备切换
在Keepalived配置文件的目录下新建一个脚本文件,添加以下内容
[root@memcache1 ~]# vim /etc/keepalived/memcached.sh
#!/bin/bash
if [ $(ps -C memcached --no-header | wc -l) -eq 0 ]
then
systemctl stop keepalived
fi
必须为该脚本添加执行权
[root@memcache2 ~]# chmod +x /etc/keepalived/memcached.sh
在102(Memcached服务器②)操作
再在102的配置文件中修改下列参数,然后把第34行以下的参数全部删除(输入位置移到第34行,按小写d大写G)
在Keepalived配置文件的目录下新建一个脚本文件,添加以下内容
[root@memcache1 ~]# vim /etc/keepalived/memcached.sh
#!/bin/bash
if [ $(ps -C memcached --no-header | wc -l) -eq 0 ]
then
systemctl stop keepalived
fi
必须为该脚本添加执行权
[root@memcache2 ~]# chmod +x /etc/keepalived/memcached.sh
然后在101和102主机Keepalived配置文件中都引入该脚本,设置执行间隔为1秒(interval 1),然后在实例中调用该脚本
在101和102操作
保存并退出,分别给两台主机启动Keepalived服务
[root@memcache1 keepalived]# systemctl start keepalived
然后等待一会使用ip a命令查看VIP是否在101主机上
101操作:
[root@memcache1 keepalived]# ip a
2: ens33:
inet 192.168.10.101/24 brd 192.168.10.255 scope global ens33
inet 192.168.10.100/32 scope global ens33
如果此时再把101主机上的Memcached服务使用pkill命令杀死
[root@memcache1 keepalived]# pkill memcached
可以发现VIP飘到102主机上了,但是在101主机恢复正常的情况下,VIP不会再飘回到101主机,因为我们在配置文件中设置了不抢占的参数(nopreempt)
测试
在103(Web服务器)操作
打开之前单节点案例时用来测试连接Memcached的网页文件, 把连接的IP改成Keepalived提供给Memcached的VIP,这样哪怕有一个Memcached故障了,也能保持整个环境的正常运行
[root@mamcached-api ~]# vim /var/www/html/test.php
案例结束