一, Memcached介绍

1.1 Memcached与常见同类软件对比

(1)Memcached是什么?

(2)Memcached的作用

1.2 互联网常见内存缓存服务软件

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

二,Memcached的用途与应用场景

2.1 Memcached常见用途工作流程

2.1.1网站读取Memcached数据时工作流程

展示了Memcached缓存系统和后端数据库系统的协作流程

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

如上图所示:使用Memcached缓存查询的数据来减少数据库压力的具体工作流程如下:

(1)Web程序首先检查客户端请求的数据是否在Memcached缓存中存在,如果存在,直接把请求的数据返回给客户端,此时不再请求后端数据库。

(2)如果请求的数据在Memcached缓存中不存在,则程序会去请求数据库服务,把从数据库中取到的数据返回给客户端,同时把新取到的数据缓存一份到Memcached缓存中。

2.1.2 网站更新Memcached数据时的工作流程

具体流程如下:

(1)当程序更新或删除数据时,会首先处理后端数据库中的数据。

(2)在处理后端数据库中数据的同时,也会通知Memcached,告诉它对应的旧数据失效,从而保证Memcached中缓存的数据始终和数据库中一致,这个数据一致性非常重要,也是大型网站分布式缓存集群最头疼的问题所在。

(3)如果是在高并发读写场合,除了要程序通知Memcached过期的缓存失效外,还可能要通过相关机制,例如在数据库上部署相关程序(如在数据库中设置触发器使用UDFs),实现当数据库有更新时就把数据更新到Memcached服务中,这样一来,客户端在访问新数据时,因预先把更新过的数据库数据复制到Memcached中缓存起来了,所以可以减少第一次查询数据库带来的访问压力,提升Memcached中缓存的命中率,甚至新浪门户还会把持久化存储Redis做成MySQL数据库的从库,实现真正的主从复制。

下图为Memcached网站作为缓存应用更新数据的流程

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

下图为Memcached服务作为缓存应用通过相关软件更新数据的流程

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

2.2 Memcached在企业中的应用场景

2.2.1 作为数据库的查询数据缓存

(1)完整数据缓存

(2)热点数据缓存

热点数据缓存一般是用于由用户更新的商品,例如淘宝的卖家,在卖家新增商品后,网站程序就会把商品写入后端数据库,同时把这部分数据,放入Memcached内存中,下一次访问这个商品的请求就直接从Memcached内存中取走了。这种方法用来缓存网站热点的数据,即利用Memcached缓存经常被访问的数据。

  • 如果碰到电商双11,秒杀高并发的业务场景,必须要事先预热各种缓存,包括前端的Web缓存和后端的数据库缓存。
  • 也就是先把数据放入内存预热,然后逐步动态更新。此时,会先读取缓存,如果缓存里没有对应的数据,再去读取数据库,然后把读到的数据放入缓存。如果数据库里的数据更新,需要同时触发缓存更新,防止给用户过期的数据,当然对于百万级别并发还有很多其他的工作要做。
  • 绝大多数的网站动态数据都是保存在数据库当中的,每次频繁地存取数据库,会导致数据库性能急剧下降,无法同时服务更多的用过户(比如MySQL特别频繁的锁表就存在此问题),那么,就可以让Memcached来分担数据库的压力。增加Memcached服务的好处除了可以分担数据库的压力以外,还包括无须改动整个网站架构,只须简单地修改下程序逻辑,让程序先读取Memcached缓存查询数据即可,当然别忘了,更新数据时也要更新Memcached缓存。

2.2.2 作为集群节点的session会话共享存储

下图为Memcached服务在企业集群架构中的常见工作位置:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

三,Memcached的特点与工作机制

3.1 Memcached的特点

Memcached作为高并发,高性能的缓存服务,具有如下特点:

  • 协议简单。Memcached的协议实现很简单,采用的是基于文本行的协议,能通过telnet/nc等命令直接操作memcached服务存储数据。
  • 支持epoll/kqueue异步I/O模型,使用libevent作为事件处理通知机制。
  • 简单的说,libevent是一套利用c开发的程序库,它将BSD系统的kqueue,Linux系统的epoll等事件处理功能封装成一个接口,确保即使服务器端的连接数增加也能发挥很好的性能。Memcached就是利用这个libevent库进行异步事件处理的。
  • 采用key/value键值数据类型。被缓存的数据以key/value键值形式存在,例如:
benet-->36,key=benet,value=36
yunjisuan-->28,key=yunjisuan,value=28
#通过benet key可以获取到36值,同理通过yunjisuan key可以获取28值
  • 全内存缓存,效率高。Memcached管理内存的方式非常高效,即全部的数据都存放于Memcached服务事先分配好的内存中,无持久化存储的设计,和系统的物理内存一样,当重启系统或Memcached服务时,Memcached内存中的数据就会丢失。
  • 如果希望重启后,数据依然能保留,那么就可以采用redis这样的持久性内存缓存系统。
  • 当内存中缓存的数据容量达到服务启动时设定的内存值时,就会自动使用LRU算法(最近最少被使用的)删除过期的缓存数据。也可以在存放数据时对存储的数据设置过期时间,这样过期后数据就自动被清除,Memcached服务本身不会监控数据过期,而是在访问的时候查看key的时间戳判断是否过期。
  • 可支持分布式集群

    Memcached没有像MySQL那样的主从复制方式,分布式Memcached集群的不同服务器之间是互不通信的,每一个节点都独立存取数据,并且数据内容也不一样。通过对Web应用端的程序设计或者通过支持hash算法的负载均衡软件,可以让Memcached支持大规模海量分布式缓存集群应用。

下面是利用Web端程序实现Memcached分布式的简单代码:

"memcached_servers" ==>array(
'10.4.4.4:11211',
'10.4.4.5:11211',
'10.4.4.6:11211',

下面使用Tengine反向代理负载均衡的一致性哈希算法实现分布式Memcached的配置。

http {

upstream test {

consistent_hash $request_uri;

server 127.0.0.1:11211 id=1001 weight=3;

server 127.0.0.1:11212 id=1002 weight=10;

server 127.0.0.1:11213 id=1003 weight=20;

}

}

3.2 Memcached工作原理与机制

3.2.1 Memcached工作原理

3.2.2 Socket事件处理机制

3.2.3 数据存储机制

3.2.4 内存管理机制

Memcached采用了如下机制:

  • 采用slab内存分配机制
  • 采用LRU对象清除机制
  • 采用hash机制快速检索item

3.2.5 多线程处理机制

多线程处理时采用的是pthread(POSIX)线程模式。

若要激活多线程,可在编译时指定:./configure --enable-threads

锁机制不够完善

负载过重时,可以开启多线程(-t 线程数为CPU核数)

3.3 Memcached预热理念及集群节点的正确重启方法

3.3.1 Memcached预热理念

3.3.2 如何正确开启网站集群服务器

四,Memcached内存管理

4.1 Memcached内存管理机制深入剖析

(1)Malloc内存管理机制

在讲解Memcached内存管理机制前,先来了解malloc

(2)Slab内存管理机制

现在的Memcached是利用Slab Allocation机制来分配和管理内存的,过程如下:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

(3)Slab Allocation的主要术语

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

(4)Slab 内存管理机制特点

  • 提前分配大内存Slab 1MB,再进行小对象填充chunk。
  • 避免大量重复的初始化和清理,减轻内存管理器负担。
  • 避免频繁malloc/free内存分配导致的碎片

下面对Mc的内存管理机制进行一个小结

  • Mc的早期内存管理机制为malloc(动态内存分配)
  • malloc(动态内存分配)产生内存碎片,导致操作系统性能急剧下降。
  • Slab内存分配机制可以解决内存碎片的问题
  • Memcached服务的内存预先分割成特定长度的内存块,称为chunk,用于缓存数据的内存空间或内存块,相当于磁盘的block,只不过磁盘的每一个block都是相等的,而chunk只有在同一个Slab Class内才是相等的。
  • Slab Class指特定大小(1MB)的包含多个chunk的集合或组,一个Memcached包含多个Slab Class,每个Slab Class包含多个相同大小的chunk。
  • Slab机制也有缺点,例如,Chunk的空间会有浪费等。

4.2 Memcached Slab Allocator内存管理机制的缺点

(1)chunk存储item浪费空间

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

-f <factor>chunk size growth factor (default:1.25)!

(2)Slab尾部剩余空间

4.3 使用Growth Factor对Slab Allocator内存管理机制调优

#memcached -f 2 w

下面是启动后的verbose输出:

slab class 1:chunk size 128 perslab 8192
slab class 2:chunk size 256 perslab 4096
slab class 3:chunk size 512 perslab 2048
slab class 4:chunk size 1024 perslab 1024
slab class 5:chunk size 2048 perslab 512
slab class 6:chunk size 4096 perslab 256
slab class 7:chunk size 8192 perslab 128
slab class 8:chunk size 16384 perslab 64
slab class 9:chunk size 32768 perslab 32
slab class 10:chunk size 65536 perslab 16
slab class 11:chunk size 131072 perslab 8
slab class 12:chunk size 262144 perslab 4
slab class 13:chunk size 524288 perslab 2

来看看现在的默认设置(f=1.25)时的输出:

slab class 1:chunk size 88 perslab 11915 <---88*11915=1048520
slab class 2:chunk size 112 perslab 9362
slab class 3:chunk size 144 perslab 7281
slab class 4:chunk size 184 perslab 5698
slab class 5:chunk size 232 perslab 4519
slab class 6:chunk size 296 perslab 3542
slab class 7:chunk size 376 perslab 2788
slab class 8:chunk size 472 perslab 2221
slab class 9:chunk size 592 perslab 1771
slab class 10:chunk size 744 perslab 1409 <---744*1409=1048520

4.4 Memcached的检测过期与删除机制

(1)Memcached懒惰检测对象过期机制

(2)Memcached懒惰删除对象机制

-M rerurn error on memory exhausted(rather than removing items)

下面针对Memcached删除机制进行一个小结

  • 不主动检测item对象是否过期,而是在get时才会检查item对象是否过期以及是否应该删除。
  • 当删除item对象时,一般不释放内存空间,而是做删除标记,将指针放入slot回收插槽,下次分配的时候直接使用。
  • 当内存空间满的时候,将会根据LRU算法把最近最少使用的item对象删除。
  • 数据存入可以设定过期时间,但是数据过期后不会被立即删除,而是在get时检查item对象是否过期以及是否应该删除。
  • 如果不希望系统使用LRU算法清除数据,可以用使用-M参数。

五,Memcached服务安装

5.1 安装libevent及连接Memcached工具nc

系统安装环境如下:

[root@cache01 ~]# cat /etc/redhat-release
CentOS release 6.5 (Final)
[root@cache01 ~]# uname -r
2.6.32-431.el6.x86_64
[root@cache01 ~]# uname -m
x86_64

安装Memcached前需要先安装libevent,有关libevent的内容在前文已经介绍,此处用yum命令安装libevent。操作命令如下:

[root@cache01 ~]# yum -y install libevent libevent-devel nc      #自带光盘里没有,需要公网yum源
[root@cache01 packages]# rpm -qa libevent libevent-devel nc
libevent-1.4.13-4.el6.x86_64
libevent-devel-1.4.13-4.el6.x86_64
nc-1.84-24.el6.x86_64

5.2 安装Memcached

操作命令如下:

[root@cache01 ~]# yum -y install memcached       #此处可通过光盘安装

六,Memcached服务的基本管理

6.1 启动Memcached

启动Memcached的命令如下:

[root@cache01 ~]# which memcached       #查看Memcached命令路径
/usr/bin/memcached
[root@cache01 ~]# memcached -m 16m -p 11211 -d -u root -c 8192
#启动第一个Memcached实例
[root@cache01 ~]# netstat -antup | grep 11211 #查看启动情况
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 1303/memcached
tcp 0 0 :::11211 :::* LISTEN 1303/memcached
udp 0 0 0.0.0.0:11211 0.0.0.0:* 1303/memcached
udp 0 0 :::11211 :::* 1303/memcached
[root@cache01 ~]# ps -ef | grep memcached | grep -v grep
#查看Memcached进程
root 1303 1 0 08:49 ? 00:00:00 memcached -m 16m -p 11211 -d -u root -c 8192 #启动第二个Memcached实例
[root@cache01 ~]# memcached -m 16m -p 11212 -d -u root -c 8192
[root@cache01 ~]# ps -ef | grep memcached | grep -v grep
root 1303 1 0 08:49 ? 00:00:00 memcached -m 16m -p 11211 -d -u root -c 8192
root 1317 1 0 08:55 ? 00:00:00 memcached -m 16m -p 11212 -d -u root -c 8192 #可把上述两个实例的启动命令放入/etc/rc.local,以便下次开机可以自启动
[root@cache01 ~]# tail -2 /etc/rc.local
memcached -m 16m -p 11211 -d -u root -c 8192
memcached -m 16m -p 11212 -d -u root -c 8192

6.2 Memcached启动命令相关参数说明

进程与连接设置:

-d以守护进程(daemon)方式运行服务
-u指定运行Memcached的用户,如果当前用户为root,需要使用此参数指定用户
-l指定Memcached进程监听的服务器IP地址,可以不设置此参数
-p(小写)指定Memcached服务监听TCP端口号。默认为11211
-P(大写)设置保存Memcached的pid文件($$),保存PID到指定文件

内存相关设置:

-m指定Memcached服务可以缓存数据的最大内存,默认为64MB
-MMemcached服务内存不够时禁止LRU,如果内存满了会报错
-n为key+value——flags分配的最小内存空间,默认为48字节
-fchunk size增长因子,默认为1.25
-L启用大内存页,可以降低内存浪费,改进性能

并发连接设置:

-c最大的并发连接数,默认是1024
-t线程数,默认4.由于Memcached采用的是NIO,所以太多线程作用不大
-R每个event最大请求数,默认是20
-C禁用CAS(可以禁止版本计数,减少开销)

测试参数:

-vv打印非常多调试信息和错误输出到控制台
-vvv打印极多的调试信息和错误输出,也打印内部状态转变

其他选项可通过“memcached -h”命令来显示。

6.3 向Memcached中写入数据并检查

6.3.1 Memcached中的数据形式及与MySQL相关语句对比

这里把Memcached添加,查询,删除等的命令和MySQL数据库做一个基本类比,见下表:

MySQL的insert语句Memcached的set命令
MySQL的select语句Memcached的get命令
MySQL的delete语句Memcached的delete命令

6.3.2 向Memcached中写入数据实践

(1)通过printf配合nc向Memcached中写入数据,命令如下:

[root@cache01 ~]# printf "set key1 0 0 5\r\nbenet\r\n" | nc 127.0.0.1 11211
STORED #出现STORED表示成功添加key1及对应的数据 #如果set命令的字节是6,那么后面就要6个字符(字节)。否则插入数据就会不成功。示例如下:
[root@cache01 ~]# printf "set key1 0 0 4\r\nbenet\r\n" | nc 127.0.0.1 11211
CLIENT_ERROR bad data chunk
ERROR #通过printf配置nc从Memcached中读取数据,命令如下:
[root@cache01 ~]# printf "get key1\r\n" | nc 127.0.0.1 11211
VALUE key1 0 5
benet #这就是读取到的key1对应额值 #通过printf配合nc从Memcached中删除数据,命令如下:
[root@cache01 ~]# printf "delete key1\r\n" | nc 127.0.0.1 11211
DELETED
[root@cache01 ~]# printf "get key1\r\n" | nc 127.0.0.1 11211
END

(2)通过telnet命令写入数据时,具体步骤如下:

1)安装telnet工具
yum -y install telnet 2)通过telnet向Memcached中写入数据
[root@cache01 ~]# which telnet
/usr/bin/telnet
[root@cache01 ~]# telnet 127.0.0.1 11211
Trying 127.0.0.1...
Connected to 127.0.0.1.
Escape character is '^]'.
set user01 0 0 7 #写入数据
Welcome
STORED
get user01 #浏览数据
VALUE user01 0 7
Welcome
END
delete user01 #删除数据
DELETED
get user01 #再浏览数据,数据被删除
END
quit #退出
Connection closed by foreign host.

6.4 操作Memcached相关命令的语法

以下为操作Memcached的相关命令基本语法:

     set      key1    0       0       6      \r\n     benet     \r\n
<command name><key><flags><exptime><bytes><datablock><string><datablock>
STORED
<status>

下表为操作Memcached相关命令的详细说明:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

6.5 关闭Memcached

单实例关闭Memcached的方法如下:

[root@cache01 ~]# ps -ef | grep memcached | grep -v grep
root 1473 1 0 11:11 ? 00:00:00 memcached -m 16m -p 11211 -d -u root -c 8192
[root@cache01 ~]# killall memcached或pkill memcached
[root@cache01 ~]# netstat -antup | grep 11211

若启动了多个实例Memcached,使用killall或pkill方式就会同时关闭这些实例!因此最好在启动时增加-P参数指定固定的pid文件,这样便于管理不同的实例。示例如下:

[root@cache01 ~]# memcached -m 16m -p 11211 -d -u root -c 8192 -P /var/run/11211.pid
[root@cache01 ~]# memcached -m 16m -p 11212 -d -u root -c 8192 -P /var/run/11212.pid
[root@cache01 ~]# ps -ef | grep memcached | grep -v grep
root 1486 1 0 11:14 ? 00:00:00 memcached -m 16m -p 11211 -d -u root -c 8192 -P /var/run/11211.pid
root 1493 1 0 11:14 ? 00:00:00 memcached -m 16m -p 11212 -d -u root -c 8192 -P /var/run/11212.pid #此时,即可通过kill命令关闭Memcached
[root@cache01 ~]# kill `cat /var/run/11211.pid`
[root@cache01 ~]# netstat -antup | grep 11211
[root@cache01 ~]# netstat -antup | grep 11212
tcp 0 0 0.0.0.0:11212 0.0.0.0:* LISTEN 1493/memcached
tcp 0 0 :::11212 :::* LISTEN 1493/memcached
udp 0 0 0.0.0.0:11212 0.0.0.0:* 1493/memcached
udp 0 0 :::11212 :::* 1493/memcached

6.6 企业工作场景中如何配置Memcached

七,安装Memcached客户端

7.1 LNMP PHP环境准备

7.2 Memcached缓存PHP扩展插件安装

[root@LNMP ~]# wget -q http://pecl.php.net/get/memcache-2.2.7.tgz
[root@LNMP ~]# ls
anaconda-ks.cfg install.log install.log.syslog memcache-2.2.7.tgz
[root@LNMP ~]# tar xf memcache-2.2.7.tgz -C /usr/src/
[root@LNMP ~]# cd /usr/src/memcache-2.2.7/
[root@LNMP memcache-2.2.7]# /usr/local/php/bin/phpize
Configuring for:
PHP Api Version: 20090626
Zend Module Api No: 20090626
Zend Extension Api No: 220090626
[root@LNMP memcache-2.2.7]# ./configure --enable-memcache --with-php-config=/usr/local/php/bin/php-config
[root@LNMP memcache-2.2.7]# make && make install
[root@LNMP ~]# ls -l /usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/
total 244
-rwxr-xr-x. 1 root root 246576 Aug 6 12:53 memcache.so
#最后生成了memcache.so模块就表示memcache扩展插件成功安装

7.3 配置Memcache客户端,使其生效

修改PHP的配置文件php.ini,加入Memcache客户端的配置,命令如下:

[root@LNMP ~]# cd /usr/local/php/lib/
[root@LNMP lib]# vim php.ini #添加如下两行内容到php.ini文件结尾
[root@LNMP lib]# tail -2 php.ini
extension_dir = "/usr/local/php/lib/php/extensions/no-debug-non-zts-20090626/"
extension=memcache.so

7.4 重启php-fpm服务使PHP的配置修改生效

1)检查php-fpm语法:

[root@LNMP lib]# /usr/local/php/sbin/php-fpm -t
[06-Aug-2017 13:03:04] NOTICE: configuration file /usr/local/php5.3.28/etc/php-fpm.conf test is successful

2)重启fpm,命令如下:

[root@LNMP lib]# pkill php-fpm
[root@LNMP lib]# netstat -antup | grep 9000
[root@LNMP lib]# /usr/local/php/sbin/php-fpm
[root@LNMP lib]# netstat -antup | grep 9000
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 46848/php-fpm

3)打开浏览器访问phpinfo页面,若出现如下图所示内容,则表示Memcache客户端安装成功

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

7.5 编写测试Memcached服务的PHP脚本

下面为简单的PHP程序连接Memcached测试脚本

[root@LNMP bbs]# cat op_mem.php
<?php #PHP开始标识 $memcache = new Memcache; #创建一个Memcache对象 $memcache->connect('192.168.0.240','11211') or die ("Could not connect Mc server"); #连接Memcached服务器 $memcache->set('key','yunjisuan book'); #设置一个变量到内存中 $get=$memcache->get('key'); #从内存中取出key echo $get; #输出key值到屏幕 ?> #PHP结束标识
[root@LNMP bbs]# ls
index.html op_mem.php test_info.php test_mysql.php

Linux本地测试:

[root@LNMP bbs]# /usr/local/php/bin/php op_mem.php          #调用php解析器
yunjisuan book #对应的key的值

windows访问测试:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

八,Memcached应用管理

8.1 通过命令管理Memcached

以下通过脚本模拟用过户插入及删除数据来监控Memcached服务是否正常的示例

8.1.1 检查Memcached服务是否异常的监控脚本

脚本内容如下:

[root@cache01 scripts]# pwd
/server/scripts
[root@cache01 scripts]# cat mon_mc.sh
#!/bin/bash export MemcachedIp=$1
export MemcachedPort=$2
export NcCmd="nc $MemcachedIp $MemcachedPort"
export MD5="3fe396c01f03425cb5e2da8186eb090d" USAGE(){
echo "$0 MemcachedIp MemcachedPort"
exit 3
} [ $# -ne 2 ] && USAGE
printf "set $MD5 0 0 9\r\nyunjisuan\r\n" | $NcCmd >/dev/null 2>&1
if [ $? -eq 0 ];then
if [ `printf "get $MD5\r\n"|$NcCmd|grep yunjisuan|wc -l` -eq 1 ];then
echo "Memcached status is ok"
printf "delete $MD5\r\n"|$NcCmd >/dev/null 2>&1
exit 0
else
echo "Memcached status is error"
exit 2
fi
else
echo "Could not connect Mc server"
exit 2
fi

Memcached服务正常的情况下,测试检验脚本

[root@cache01 scripts]# sh mon_mc.sh 127.0.0.1 11211
Memcached status is ok

关闭Memcached服务,再测试脚本

[root@cache01 scripts]# kill `cat /var/run/11211.pid`
[root@cache01 scripts]# netstat -antup | grep 11211
[root@cache01 scripts]# sh mon_mc.sh 127.0.0.1 11211
Could not connect Mc server

最后开启Memcached服务,测试检验脚本

[root@cache01 scripts]# memcached -m 16m -p 11211 -d -u root -c 8192 -P /var/run/11211.pid
[root@cache01 scripts]# netstat -antup | grep 11211
tcp 0 0 0.0.0.0:11211 0.0.0.0:* LISTEN 2053/memcached
tcp 0 0 :::11211 :::* LISTEN 2053/memcached
udp 0 0 0.0.0.0:11211 0.0.0.0:* 2053/memcached
udp 0 0 :::11211 :::* 2053/memcached
[root@cache01 scripts]# sh mon_mc.sh 127.0.0.1 11211
Memcached status is ok

8.1.2 通过nc命令查看Memcached服务的运行状态信息

查看Memcached服务运行状态信息的nc命令如下:

[root@cache01 scripts]# printf "stats\r\n"|nc 127.0.0.1 11211
STAT pid 2053
STAT uptime 225
STAT time 1502044003
STAT version 1.4.4
STAT pointer_size 64
STAT rusage_user 0.002999
STAT rusage_system 0.005999
STAT curr_connections 10
STAT total_connections 14
STAT connection_structures 11
STAT cmd_get 1
STAT cmd_set 1
STAT cmd_flush 0
STAT get_hits 1
STAT get_misses 0
STAT delete_misses 0
STAT delete_hits 1
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 141
STAT bytes_written 77
STAT limit_maxbytes 16777216
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT bytes 0
STAT curr_items 0
STAT total_items 1
STAT evictions 0
END
stats统计Memcached的各种信息
stats settings查看一些memcached的设置信息,例如:线程数
stats slabs查看slabs相关情况,例如:chunksize长度
stats items查看items相关情况
stats sizes查看items个数和大小
stats reset清理统计数据
[root@LNMP ~]# which telnet
/usr/bin/telnet
[root@LNMP ~]# telnet 192.168.0.240 11211
Trying 192.168.0.240...
Connected to 192.168.0.240.
Escape character is '^]'.
stats
STAT pid 2053 #启动的进程id
STAT uptime 682 #到目前1位置启动了多少秒
STAT time 1502044460
STAT version 1.4.4 #Memcached的版本信息
STAT pointer_size 64
STAT rusage_user 0.007998
STAT rusage_system 0.014997
STAT curr_connections 10 #当前的并发连接数
STAT total_connections 15 #总的连接数
STAT connection_structures 11
STAT cmd_get 1 #执行的get命令的次数
STAT cmd_set 1 #执行的set命令的次数
STAT cmd_flush 0 #执行flush命令的次数
STAT get_hits 1 #get的命中数
STAT get_misses 0 #get的非命中数
STAT delete_misses 0
STAT delete_hits 1
STAT incr_misses 0
STAT incr_hits 0
STAT decr_misses 0
STAT decr_hits 0
STAT cas_misses 0
STAT cas_hits 0
STAT cas_badval 0
STAT auth_cmds 0
STAT auth_errors 0
STAT bytes_read 148
STAT bytes_written 848
STAT limit_maxbytes 16777216 #允许使用的最大内存容量
STAT accepting_conns 1
STAT listen_disabled_num 0
STAT threads 4
STAT conn_yields 0
STAT bytes 0
STAT curr_items 0
STAT total_items 1
STAT evictions 0
END

使用printf及nc命令获取状态信息更佳,因为无需交互,可以使用以下脚本批量操作

[root@LNMP ~]# printf "stats\r\n"|nc 192.168.0.240 11211
STAT pid 2053
STAT uptime 1270
STAT time 1502045048
STAT version 1.4.4
STAT pointer_size 64
STAT rusage_user 0.011998
STAT rusage_system 0.029995
STAT curr_connections 10
STAT total_connections 24
STAT connection_structures 11
#以下省略若干...

8.2 Memcached状态信息详细说明

Memcached状态信息的详细说明,同学们可以通过该表来了解相关信息:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

8.3 通过memadmin php 工具展示Memcached状态信息

8.3.1 部署memadmin php工具

部署的关键命令如下:

[root@LNMP ~]# ls -l memadmin-1.0.12.tar.gz
-rw-r--r--. 1 root root 196734 Aug 6 14:55 memadmin-1.0.12.tar.gz
[root@LNMP ~]# tar xf memadmin-1.0.12.tar.gz
[root@LNMP ~]# mv memadmin /usr/local/nginx/html/bbs/

8.3.2 采用IP或者解析好的域名进行访问

LNMP服务器的nginx.conf配置文件内容如下:

[root@LNMP nginx]# cat conf/nginx.conf
worker_processes 1;
events {
worker_connections 1024;
}
http {
include mime.types;
default_type application/octet-stream;
sendfile on;
keepalive_timeout 65;
server {
listen 80;
server_name www.yunjisuan.com;
location / {
root html/www;
index index.html index.htm;
}
}
server {
listen 80;
server_name bbs.yunjisuan.com;
location / {
root html/bbs;
index index.html index.htm;
}
location ~ .*\.(php|php5)$ {
root html/bbs;
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
include fastcgi.conf;
}
}
}

打开浏览器输入域名:http://bbs.yunjisuan.com/memadmin/index.php

程序的管理页面如下图所示:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

登陆之后的页面如下图所示:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

然后点击管理,进入下图:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

九,Memcached服务应用的优化

9.1 Memcached服务应用优化案例

[root@LNMP ~]# uptime

10:41:01 up 15:02, 4 users, load average: 20, 15, 10

#登陆数据库后,使用“show full processlist;”查看,或者在Linux命令行使用下面的命令查看:
mysql -uroot -p123123 -e "show full processlist"|grep -vi sleep

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

大概的优化方案思路如下:

  1. 看是否可以从业务上整改,例如,只有在用户登陆后才可以进行搜索,通过这种改进来减少搜索的次数,达到减轻数据库服务压力的目的。
  2. 如果有大量频繁的搜索SQL语句,很有可能是有网络爬虫在爬我们的网站,可以通过分析Web日志或者网络连接状态,封掉这些非正常的搜索请求。
  3. 为主库配置多个从库,然后实现数据的读写分离,让“LIKE‘%杜冷丁%’”这样的查询去多个从库查,从而减轻主库的读写压力。
  4. 在数据库前端加Memcached缓存服务器,这个效果在所有的方法里是最好的。
  5. 在数据库里使用“LIKE‘%杜冷丁%’”实现搜索,并非明智的选择,可以通过Sphinx等搜索服务实现用户搜索。
  6. 还可以利用C,Ruby等开发语言开发程序,部署计算服务器实现每日读数据库计算全量搜索索引,然后保存在提供搜索的Web服务器上,除了设定每日计算全量搜索索引外,可以每分钟读单独的1~2个从库做增量计算索引。这是大公司针对站内搜索采取的基本解决方案之一。

下图是针对方案6给出的大型网站搜索集群架构逻辑案例图

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

9.2 Memcached服务优化策略

9.2.1 提高Memcached访问命中率是优化的最关键指标。

9.2.2 提高内存利用率,减少内存浪费

  • 减少chunk内存空间浪费的调优方法为,根据业务数据的大小,利用-n参数设定chunk的初始值,及通过-f参数factor增长因子设置chunk的大小尽可能接近业务数据的大小。
  • 减少slab的浪费,设定slab的大小为chunk的整数倍。
  • 采用一致性哈希分布式缓存集群架构

9.3 Memcached服务在大型站点中的架构优化

9.3.1 大型网站的架构设计原则

9.3.2 大型网站的数据库架构常见设计

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

9.3.3 分布式Memcached缓存服务架构

(1)缓存服务器使用常规负载均衡模式的问题

  • 当客户端访问缓存A无数据时,就会去查后端数据库,然后把查到的数据放入缓存A中一份,当下次客户端访问相同的数据时,可能被分配到的是缓存B,结果B中还是无数据,这样客户端又会去查后端数据库,这样就会给数据库造成了访问压力,同时造成缓存服务器的命中率很低。
  • 在集群运行一段时间后,所有缓存的数据可能交叉并极其接近,如果数据库数据量远大于单台Memcached服务器的内存总量,Memcached的命中率也会非常低下。理想的情况是所有缓存数据之和接近数据库总的数据容量,这样缓存的效率才会高。
  • 解决上述问题的方案最常见的就是使用哈希算法或一致性哈希算法将需要同样数据的请求始终调度到同一台缓存服务器,提升访问命中率。其次,所有缓存服务器缓存的数据都是不同的,所有服务器缓存的数据之和接近数据库总的数据容量,使得缓存集群无需换入换出,达到更高的命中率。

下图是缓存服务器使用常规负载均衡模式的问题图解

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

(2)分布式缓存集群的优劣势

9.3.4 分布式缓存集群设计思想

1)每一台Memcached服务器的内容都是不一样的。这些Memcached服务器缓存的内容加起来接近整个数据库的数据容量。

2)通过在客户端程序或者Memcached的负载均衡器上用hash算法,让同一数据内容都分配到一个Memcached服务器。

3)普通的hash算法对于节点宕机会带来大量的缓存数据流动(失效),可能会引起雪崩效应。

4)一致性哈希算法(还可以带虚拟节点)可以让缓存节点宕机对节点的数据流动(失效)降到最低。

9.3.5 分布式Memcached缓存集群的调度算法

(1)取模计算hash

优点:简单,分散性优秀

缺点:添加/删除服务器时,缓存重组代价巨大,影响命中率

例:将26个字母缓存到了3个节点,此时新增加一个节点,访问命中率将下降23%如下表:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

(2)Consistent hash(一致性哈希算法)

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

假如我们要添加node5服务器,如下图所示:

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

十,Memcached在集群中session共享案例

10.1 Memcached在集群中的session共享存储实战

以下是PHP Web环境集群的session共享存储设置。

#默认php.ini中session的类型和配置路径为:
[root@LNMP ~]# awk '/session.save_handler/{print NR,$0}/session.save_path/{print NR,$0}' /usr/local/php/lib/php.ini
1461 session.save_handler = files #修改本行数据
1469 ; session.save_path = "N;/path"
1485 ; session.save_path = "N;MODE;/path"
1490 ;session.save_path = "/tmp" #修改本行数据
1566 ; (see session.save_path above), then garbage collection does *not* #修改成如下配置:
[root@LNMP ~]# sed -n '1461p;1490p' /usr/local/php/lib/php.ini
session.save_handler = memcache
session.save_path = "tcp://192.168.0.240:11211" #重启php-fpm服务
[root@LNMP ~]# pkill php-fpm
[root@LNMP ~]# netstat -antup | grep 9000
[root@LNMP ~]# /usr/local/php/sbin/php-fpm
[root@LNMP ~]# netstat -antup | grep 9000
tcp 0 0 127.0.0.1:9000 0.0.0.0:* LISTEN 1393/php-fpm

Linux实战教学笔记32:企业级Memcached服务应用实践-LMLPHP

10.2 Memcached在集群中的session共享存储的优缺点

优点:

1)读写速度上会比普通files速度快很多

2)可以解决多个服务器共用session的难题

缺点:

1)session数据都保存在memory中,持久化方面有所欠缺,但对session数据来说不是问题。

2)一般是单台,如果部署多台,多台之间无法数据同步。通过hash算法分配依然有session丢失的问题。

对于上面的缺点,解决思路如下:

1)可以用其他的持久化系统存储sessions,例如:redis,ttserver来替代Memcached

2)高性能高并发场景,cookies效率比session要好很多,因此,大网站都会用cookies解决会话共享问题

3)有的已经就业了的同学通过牺牲LB的负载均衡的策略实现,例如:lvs-p,nginx ip_hash等,但这些不是好的方法。

十一,本章重点回顾

  1. Memcached在企业中的应用场景案例
  2. Memcached企业中常见用途读写工作流程
  3. Memcached特性与工作原理机制
  4. Memcached内存管理核心机制
  5. Memcached检测过期与删除工作原理机制
  6. Memcached服务器端安装与应用实践
  7. Memcached客户端插件安装及配置
  8. Memcached的运行状态信息监控
  9. Memcached服务应用优化策略及案例
  10. Memcached在集群后端作为session共享案例
05-02 12:54