一、原理

1.1:概述

Memcached 是一套开源的高性能分布式内存对象缓存系统,它将所有的数据都存储在内存中,因为内存中会统一维护一张巨大的Hash 表,所以支持任意存储类型的数据。很多网站使用emcached 提高网站的访问速度,尤其是需要频繁访问数据的大型网站。

Memcached 是典型的C/S 架构,因此需要构建Memcached 服务器端与MemcachedAPI客户端。Memcached 服务器端是用C 语言编写的,而Memcached API 客户端可用任何语言来编写(如PHP、Python、Perl 等),并通过Memcached 协议与Memcached 服务器端进行通信。


1.2:案例前置知识点

1:数据存储方式与数据过期方式
(1)数据存储方式:Slab Allocation

Slab Allocation 即按组分配内存,每次先分配一个Slab,相当于一个大小为1M的页。然后,在1M 的空间里根据数据划分大小相同的Chunk,该方法可以有效解决内存碎片问题,但也可能会使内存空间产生浪费。


(2)数据过期方式:LRU、Laxzy Expiration

LUR 是指追加的数据空间不足时,会根据LRU 的情况淘汰最近最少使用的记录。

Laxzy Expiration 即惰性过期,是指使用get 时查看记录时间,从而检查记录是否已经过期。


2:Memcached 缓存机制

缓存是常驻在内存的数据,能够快速进行读取,而Memcached 就是这样一款非常出色的缓存软件。当程序写入缓存数据请求时,Memcached 的API 接口将Key 输入路由算法模块并路由到集群中的一台服务器,之后由API 接口与服务器进行通信,完成一次分布式缓存写入。


3:Memcached 分布式

Memcached分布式部署主要依赖于Memcached的客户来端实现,多个Memcached 服务器是独立的。分布式数据如何存储是由路由算法所决定。当数据到达客户端程序库,客户端的算法就依据路由算法来决定保的Memcached 服务器。读取数据时,客户端依据使用保存数据时相同的路由算法选中和存储数据时相同的服务器来读取数据。

 

4:Memcached 路由算法
(1)求余数hash 算法
(2)一致性hash 算法


1.3:案例环境

1:本案例环境

主机

操作系统

主机名/IP地址

主要软件及版本

服务器

Centos7.9

Memcache1/192.168.10.101

libevent-2.1.8-stable.tar.gz

memcached-1.5.1.tar.gz

memcached-1.2.8-repcached-2.2.tar.gz

服务器

Centos7.9

Memcache2/192.168.10.102

libevent-2.1.8-stable.tar.gz

memcached-1.2.8-repcached-2.2.tar.gz

客户端

Centos7.9

Memcached-API/192.168.10.103

httpd-2.4.25.tar.gzphp-5.5.38.tar.gz

libmemcached-1.0.18.tar.gz

memcached-2.2.0.tgz


2:案例拓扑

高性能内存对象缓存Memcached原理与部署_php


二、案例一:单memcached节点缓存系统

2.1:设置各节点的主机名

主机:192.168.10.101

[root@localhost ~]# hostnamectl set-hostname Memcache1

[root@localhost ~]# bash


主机:192.168.10.102

[root@localhost ~]# hostnamectl set-hostname Memcache2

[root@localhost ~]# bash


主机:192.168.10.103

[root@localhost ~]# hostnamectl set-hostname Memcached-API

[root@localhost ~]# bash


2.2:安装 Memcached 服务器

1:安装 Libevent

[root@memcache1 ~]# systemctl stop firewalld

[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

备注:

Libevent 是一个用C语言编写的、轻量级的开源高性能事件通知库,主要有以下几个亮点:事件驱动( event-driven),高性能;轻量级,专注于网络,不如 ACE 那么臃肿庞大;源代码相当精炼、易读;跨平台,支持 Windows、 Linux、 *BSD 和 Mac Os;支持多种 I/O 多路复用技术, epoll、 poll、 dev/poll、 select 和 kqueue 等;支持 I/O,定时器和信号等事件;注册事件优先级。

Libevent 已经被广泛的应用,作为底层的网络库;比如 memcached、 Vomit、 Nylon、 Netchat等等。


2:安装 Memcached

[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


3:设置Memcached 服务脚本

[root@memcache1 ~]# vim /usr/local/memcached/memcached_service.sh

#!/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 ~]# yum -y install psmisc

备注:

psmisc提供了killall命令

[root@memcache1 ~]# chmod 755 /usr/local/memcached/memcached_service.sh

[root@memcache1 ~]# /usr/local/memcached/memcached_service.sh start

[root@memcache1 ~]# netstat -anpt | grep memcached

tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      20564/memcached     

tcp6       0      0 :::11211                :::*                   LISTEN      20564/memcached  


2.3:Memcached API 客户端

注意:

设置好阿里yum源

yum -y install httpd mariadb mariadb-server phpphp-devel php-mysql

systemctl start mariadb

mysqladmin -u root password 'pwd123'

systemctl start httpd


cat <<EOF>/var/www/html/test1.php

<?php

phpinfo();

?>

EOF


1:编译安装 Libmemcached

[root@memcached-api ~]# systemctl stop firewalld

[root@memcached-api ~]# setenforce 0


[root@memcached-api ~]# yum -y install gcc*

[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

备注:

libmemcached 是一个 memcached 的库,客户端库,C 和 C++ 语言实现的客户端库,具有低内存占用率、线程安全、并提供对memcached功能的全面支持


2:编译安装 Memcached 扩展
(1)如果lamp是用源码包安装的,使用如下方法

[root@memcached-api ~]# tar -xzvf memcached-2.2.0.tgz

[root@memcached-api ~]# cd memcached-2.2.0/


[root@memcached-api memcached-2.2.0]# /usr/local/php5/bin/phpize

备注:

此命令可以在memcached-2.2.0下生成memcached的配置脚本

phpize命令需要autoconf包的支持 :yum -y install autoconf


[root@memcached-api memcached-2.2.0]# cp -r /usr/local/php5/include/php/ext/ ./

[root@memcached-api memcached-2.2.0]# ./configure \

--enable-memcached \

--with-php-cnotallow=/usr/local/php5/bin/php-config \

--with-libmemcached-dir=/usr/local/libmemcached \

--disable-memcached-sasl


[root@memcached-api memcached-2.2.0]# make

[root@memcached-api memcached-2.2.0]# make test

注意:

最后会提示发送邮件报告,可以选否(n)

[root@memcached-api memcached-2.2.0]# make install


(2)如果lamp是用yum安装的,使用如下方法

如果是用yum安装的lamp环境,使用如下方法安装 Memcached 扩展

[root@memcached-api ~]# yum -y install zlib zlib-devel

[root@memcached-api ~]# tar -xzvf memcached-2.2.0.tgz

[root@memcached-api ~]# cd memcached-2.2.0/

[root@memcached-api memcached-2.2.0]# /usr/bin/phpize

[root@memcached-api memcached-2.2.0]# ./configure --with-php-cnotallow=/usr/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached --disable-memcached-sasl --with-zlib-dir

备注:

1. SASL全称Simple Authentication and Security Layer,是一种用来扩充C/S模式验证能力的机制。简单来说SASL是一个胶合(glue)库,通过这个库把应用层与形式多样的认证系统整合在一起。这有点类似于 PAM,但是后者是认证方式,决定什么人可以访问什么服务,而SASL是认证过程,侧重于信任建立过程,这个过程可以调用PAM来建立信任关系。在这里Memcached就是上面提到的应用层,具体的认证交给SASL库,SASL会根据相应的认证机制来完成验证功能。

[root@memcached-api memcached-2.2.0]# make && make install


备注:

如果安装的是php7的版本,会报错:php_smart_str.h: No such file or directory


3:配置PHP 添加Memcached 组件
(1)添加Memcached

[root@memcached-api ~]# cd /usr/local/php5/

[root@memcached-api php5]# vim php.ini

extension_dir = "/usr/local/php5/lib/php/extensions/no-debug-zts-20121212/"

extensinotallow=memcached.so

备注:

如果使用的yum安装的php,

[root@memcache2 ~]# vim /etc/php.ini

去掉extension_dir=" "

只添加extensinotallow=memcached.so

[root@memcached-api php5]# systemctl restart httpd


(2)通过PHPinfo 查看是否已经添加Memcached 扩展模块

使用浏览器进行访问


4:测试Memcached-API 功能

[root@memcached-api ~]# vim /usr/local/httpd/htdocs/test2.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;

?>

备注:

如果是用yum安装的lamp,此文件所在的目录在/var/www/html

访问测试:http://192.168.10.103/test2.php


2.4:Memcached 数据库操作与管理

[root@memcache1 ~]# yum -y install telnet

[root@memcache1 ~]# telnet 127.0.0.1 11211


1:添加一条键值数据

add username 0 0 8 

zhangsan 

STORED

备注:

表示键值名为username,

标记位表示自定义信息为0,

过期时间为0(永不过期,单位为秒)

字节数为8;

 zhangsan 为值,这里需要注意输入长度为8 字节,与设定值符合


2:查询键值数据

get username

VALUE username 0 8 

zhangsan 

END

gets username

VALUE username 0 8 2 

zhangsan 

END

备注:

get 后跟键名。如果检查最近是否更新,可以使用gets,最后一位显示的是更新因子,每更新一次更新因子数会加一


3:更新一条键值数据

set username 0 0 4 

lisi 

STORED

get username

VALUE username 0 4 

everything

END


gets username

VALUE username 0 4 4

lisi

END


4:清除一条缓存数据

delete username

DELETED

get username 

END


5:检查后更新check and set

add username 0 0 8

zhangsan

STORED


gets username

VALUE username 0 8 7 

zhangsan 

END


cas username 0 0 8 1 ##注意,因为更新因子和gets得到的不一致,这个语句的更新会失败

lodging

EXISTS


cas username 0 0 8 7 

zhangsai 

STORED

gets username

VALUE username 0 7 8

lodging

END

备注:

cas命令的最后一个数字是更新因子,如果gets获取到的更新因子和cas命令提供的更新因子一致,则更新改数据,否则不会更新,会提示exists


cas命令的第三个数字是要更新的数据的字节数,和接下来输入进去的字符串的字节数要一致,否则会报错


6:追加数据

append username 0 0 8 //后追加8 字节

zhangsan 

STORED

get username

VALUE username 0 14

lodgingzhangsan 

END


7:清除所有缓存数据

flush_all

OK


8:查看服务器统计信息
  • stats
  • stats items      //返回所有键值对统计信息
  • stats cachedump 1 0    //返回指定存储空间的键值对
  • stats slabs     //显示各个slab 的信息,包括chunk 的大小、数目、使用情况等
  • stats sizes     //输出所有item 的大小和个数
  • stats reset     //清空统计数据


9:退出

quit


三、案例二:Memcached 实现主主复制和高可用的方式

3.1:Memcached 主主复制架构

Memcached 的复制功能支持多个Memcached 之间相互复制(双向复制,主备都是可读可写的),可以解决Memcached 的容灾问题。


1:安装带有复制功能的 Memcached

(此步骤在两台memcache服务器上都执行)

(1):安装 Libevent

[root@memcache1 ~]# systemctl stop firewalld

[root@memcache1 ~]# setenforce 0


[root@memcache1 ~]# yum -y install gcc* psmisc

[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


(2)安装memcached-1.2.8-repcached

[root@memcache1 ~]# tar zxvf memcached-1.2.8-repcached-2.2.tar.gz

[root@memcache1 ~]# cd memcached-1.2.8-repcached-2.2

[root@Memcached1 memcached-1.2.8-repcached-2.2]# ./configure\

--prefix=/usr/local/memcached_replication\

--enable-replication\

--with-libevent=/usr/local/libevent


[root@memcache1 memcached-1.2.8-repcached-2.2]# vim memcached.c

#找到如下几行(在55行--60行):

/* FreeBSD 4.x doesn't have IOV_MAX exposed. */

#ifndef IOV_MAX

#if defined(__FreeBSD__) || defined(__APPLE__)

# define IOV_MAX 1024

#endif

#endif


#修改成如下所示:(删掉上面红色的两行)

/* FreeBSD 4.x doesn't have IOV_MAX exposed. */

#ifndef IOV_MAX

# define IOV_MAX 1024

#endif



[root@memcache1 memcached-1.2.8-repcached-2.2]# make && make install


2:启动 Memcached 服务
(1)在memcache1上启动

[root@memcache1 ~]# ln -s /usr/local/libevent/lib/libevent-2.1.so.6 /usr/lib64/

[root@Memcached1 ~]# /usr/local/memcached_replication/bin/memcached -d -u root -m 128 -x 192.168.10.102

注意:

启动时要指向对端

  • -d:守护进程方式启动
  • -u:指定用户
  • -x:指定对端服务器的地址
  • -m:最大的内存使用单位是MB 默认是64MB


(2)在memcache2上启动

[root@memcache1 ~]# ln -s /usr/local/libevent/lib/libevent-2.1.so.6 /usr/lib64/

[root@Memcached1 ~]# /usr/local/memcached_replication/bin/memcached -d -u root -m 128 -x 192.168.10.101

备注:

  • -x 对方IP
  • -p <num> 监听的TCP端口(默认: 11211)
  • -U <num> UDP监听端口 (默认: 11211, 0 时关闭)
  • -d 以守护进程方式运行
  • -u <username> 运行运行 Memcached的账户 非root用户
  • -m <num> 最大的内存使用单位是MB 默认是64MB
  • -c <num> 软连接数量默认是1024
  • -v 输出警告和错误信息
  • -vv 打印客户端的请求和返回信息
  • -h 打印帮助信息-i 打印memcached和libevent的版权信息
  • -l <ip_addr> 绑定地址 (默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问)
  • -P <file> 将PID写入文件<file>,这样可以使得后边进行快速进程终止, 需要与 -d 一起使用


(3)在两台服务器上检查进程

[root@memcache1 ~]# netstat -antp |grep memcached

tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      52646memcached     

tcp        0      0 192.168.10.101:11212    192.168.10.102:38298    ESTABLISHED 52646memcached     

tcp6       0      0 :::11211                :::*                    LISTEN      52646memcached


[root@memcache2 ~]# netstat -antp |grep memcached

tcp        0      0 0.0.0.0:11211           0.0.0.0:*               LISTEN      29976memcached     

tcp        0      0 192.168.10.102:38298    192.168.10.101:11212    ESTABLISHED 29976memcached     

tcp6       0      0 :::11211                :::*                    LISTEN      29976memcached


3:使用 telnet 进行简单验证复制功能
(1)在Memcached1 上插入一条具有特点的键值

[root@memcache1 ~]# yum -y install telnet

[root@memcache1 ~]# telnet 192.168.10.102 11211

set username 0 0 8#自定义信息+永不过期+8个字节

12345678

STORED

get username

VALUE username 0 8

12345678

END

quit


(2)在Memcached2 上进行查看刚刚插入的键值

[root@memcache2 ~]# yum -y install telnet

[root@memcache2 ~]# telnet 192.168.10.102 11211

get username

VALUE username 0 8

12345678

END

gets username

VALUE username 0 8 1#1代表更新因子,

12345678

END

cas username 0 0 8 1 #自定义信息+永不过期+8个字节+更新因子(要与gets得到的一致)

zhangsan

STORED


(3)在Memcached1 上查看复制的情况

[root@localhost ~]# telnet 192.168.10.101 11211

Trying 192.168.10.101...

Connected to 192.168.10.101.

Escape character is '^]'.

get username

VALUE username 0 8

zhangsan

END


3.2:Memcached 主主复制+Keepalived 高可用架构

1:安装配置keepalived(两台主机都安装)

[root@memcache1 ~]# yum -y install keepalived


(1)配置主keepalived

[root@memcache1 ~]# vim /etc/keepalived/keepalived.conf

! Configuration File for keepalived


global_defs {

   notification_email {

     acassen@firewall.loc

     failover@firewall.loc

     sysadmin@firewall.loc

   }

   notification_email_from Alexandre.Cassen@firewall.loc

   smtp_server 192.168.200.1

   smtp_connect_timeout 30

   router_id LVS_01

   vrrp_skip_check_adv_addr

   #vrrp_strict

   vrrp_garp_interval 0

   vrrp_gna_interval 0

}


vrrp_script check_down {##定义要执行的脚本

script "/etc/keepalived/memcached.sh" ##脚本路径和名称

interval 1 ##间隔1秒执行一次

}



vrrp_instance VI_1 {

    state BACKUP      ##master角色不能设置nopreempt,所以此处要设置为BACKUP

    interface ens33

    virtual_router_id 51

    priority 100##从主机的优先级要小于此数字

advert_int 1

nopreempt ##添加,此语句关闭了抢占功能,从主机不需要

    authentication {

        auth_type PASS

        auth_pass 1111

    }

    virtual_ipaddress {

        192.168.10.100

}


track_script { ##调用前面的脚本

 check_down

}


}

备注:

vrrp_strict:严格遵守VRRP协议,禁止以下状况:1.无VIP地址 2.配置了单播邻居 3.在VRRP版本2中有IPv6地址,开启动此项会自动开启iptables防火墙规则,建议关闭此项配置


[root@memcached1 keepalived]# vim /etc/keepalived/memcached.sh

#!/bin/bash

#

if [ $(ps -C memcached --no-header | wc -l) -eq 0 ]; then

       systemctl stop keepalived

fi


[root@memcached1 keepalived]# chmod +x /etc/keepalived/memcached.sh


(2)配置从keepalived

[root@memcache2 ~]# vim /etc/keepalived/keepalived.conf

! Configuration File for keepalived


global_defs {

   notification_email {

     acassen@firewall.loc

     failover@firewall.loc

     sysadmin@firewall.loc

   }

   notification_email_from Alexandre.Cassen@firewall.loc

   smtp_server 192.168.200.1

   smtp_connect_timeout 30

   router_id LVS_02

   vrrp_skip_check_adv_addr

   #vrrp_strict

   vrrp_garp_interval 0

   vrrp_gna_interval 0

}


vrrp_script check_down {##定义要执行的脚本

script "/etc/keepalived/memcached.sh" ##脚本路径和名称

interval 1 ##间隔1秒执行一次

}



vrrp_instance VI_1 {

    state BACKUP      

    interface ens33

    virtual_router_id 51

    priority 99##从主机的优先级要小于此数字

advert_int 1

    authentication {

        auth_type PASS

        auth_pass 1111

    }

    virtual_ipaddress {

        192.168.10.100

}


track_script { ##调用前面的脚本

 check_down

}


}




[root@memcached2 keepalived]# vim /etc/keepalived/memcached.sh


#!/bin/bash

#

if [ $(ps -C memcached --no-header | wc -l) -eq 0 ]; then

       systemctl stop keepalived

fi


[root@memcached2 keepalived]# chmod +x /etc/keepalived/memcached.sh


备注:

vrrp_strict #严格遵守VRRP协vim议

这将禁止VIPs unicast peers (虚拟IP单播对等体),这样会使得这个VIP无法进行单播通信


2:测试验证
(1)在两台服务器上启动keepalived

[root@Memcached1 ~]# systemctl start keepalived

[root@memcached2 ~]# systemctl start keepalived


(2)在客户端修改缓存服务器地址

[root@memcached-api ~]# vim /usr/local/httpd/htdocs/test3.php

<?php

$memcache = new Memcached();

$memcache->addServer('192.168.10.100', 11211);

$memcache->set('key', 'Memcache test successful!', 0, 60);

$result = $memcache->get('key');

unset($memcache);

echo $result;

?>

注意:

如果是yum安装的httpd,次此文件在/var/www/html目录下


(3)浏览器访问测试

备注:

pkill memcached

检查当前主机的memceched进程和keepalived进程,

关闭memcached后,该主机的keepalived也会被脚本关闭,于是VIP就漂移到了另一台主机,待此主机修好后,把memcached和keepalived开启,由于设置了不抢占,VIP不会抢占回来,但是把第二台主机的memcached关闭后,第二台主机的keepalived也会关闭,于是VIP就漂移回了第一台主机。完成故障的转移。